User:DressyPear4/TextoCaixaAlta

From OpenStreetMap Wiki
Jump to navigation Jump to search

Correção de nomes em formato de título

Um script para correção de nomes em lote, funciona para linhas, nós e polígonos.

Tags alvo = name, alt_name, old_name, official_name, loc_name, reg_name.

Palavras podem ser ajustadas no código, Dr.=Doutor, Prof.=Professor, etc... Criado para uso especifico no Brasil, para outro país o código deve ser adaptado

Como funciona?

  • Selecione elementos do mapa
  • Execute o código
  • Confira as correções na lista

Demonstração

Imagem.gif, clique para visualizar.

Código

Python

Última atualização: 2026-03-31

from org.openstreetmap.josm.data.osm import OsmPrimitive
from org.openstreetmap.josm.gui import MainApplication, Notification
from org.openstreetmap.josm.command import ChangePropertyCommand, SequenceCommand
from org.openstreetmap.josm.data.UndoRedoHandler import getInstance
from javax.swing import UIManager, JOptionPane
import re

def title_case(text):
    ignore_words = {"da", "das", "de", "do", "dos"}
    siglas_conhecidas = {
        "br", "sp", "rj", "mg", "rs", "es", "df", "go", "sc", "pr",
        "to", "pi", "pa", "ce", "pe", "ap", "am", "ro", "rr", "ac",
        "ma", "pb", "rn", "ba", "se", "al", "mt", "ms", "to",
        "onu", "ibge", "dnit", "der",
        "lt", "ld"
    }

    correcoes_conhecidas = {
        "av.": "Avenida",
        "r.": "Rua",
        "tv.": "Travessa",
        "rod.": "Rodovia",
        "est.": "Estrada",
        "prof.": "Professor",
        "dr.": "Doutor"
    }

    # Expansão de abreviações com números/letras depois do ponto
    def expandir_abreviacoes(txt):
        for abrev, expandido in correcoes_conhecidas.items():
            padrao = r"\b" + re.escape(abrev) + r"\s*([a-z0-9]+)"
            txt = re.sub(padrao, expandido + r" \1", txt, flags=re.IGNORECASE)
        return txt

    text = expandir_abreviacoes(text)

    def is_sigla(word):
        limpo = word.lower().replace("-", "").replace("_", "")
        return limpo in siglas_conhecidas or re.match(r"^[a-z]{2,}[-\d]+$", limpo)

    words = text.split()

    def tratar(word, is_first):
        original = word.strip()
        lower = original.lower()

        # Sigla conhecida ou padrão tipo BR-101 → manter em caixa alta
        if is_sigla(original):
            return original.upper()

        # Corrigir palavra individual isolada (sem número/letra depois)
        if lower in correcoes_conhecidas:
            return correcoes_conhecidas[lower]

        # Palavra ignorada (de, da, etc.) minúscula, exceto se for a primeira
        if lower in ignore_words and not is_first:
            return lower

        # Palavras com hífen (ex: joao-pedro)
        if "-" in original:
            return "-".join(tratar(p, False) for p in original.split("-"))

        # Capitalizar normalmente
        return lower.capitalize()

    return " ".join(tratar(w, i == 0) for i, w in enumerate(words))

def adjust_name_tags():
    layer = MainApplication.getLayerManager().getEditLayer()

    if layer is None or not hasattr(layer, "data"):
        Notification(u"Nenhuma camada de edição ativa encontrada.")\
            .setIcon(UIManager.getIcon("OptionPane.errorIcon"))\
            .show()
        return

    dataset = layer.data
    selection = list(dataset.getSelectedNodes()) + \
                list(dataset.getSelectedWays()) + \
                list(dataset.getSelectedRelations())

    if not selection:
        Notification("Nenhum objeto com nome selecionado.")\
            .setIcon(UIManager.getIcon("OptionPane.warningIcon"))\
            .show()
        return

    tags_alvo = {"name", "alt_name", "old_name", "official_name", "loc_name", "reg_name"}

    commands = []
    alteracoes_texto = []

    for obj in selection:
        keys = obj.getKeys()
        for key, value in keys.items():
            if (key in tags_alvo or key.startswith("name:")) and value:
                ajustado = title_case(value)
                if ajustado != value:
                    alteracoes_texto.append(u"%s%s" % (value, ajustado))
                    commands.append(ChangePropertyCommand(obj, key, ajustado))

    if commands:
        getInstance().add(SequenceCommand("Ajustar nomes em formato titulo", commands))
        resumo = "\n".join(alteracoes_texto)
        if len(resumo) > 250:
            resumo = resumo[:250] + "\n...\n(mais alterações ocultadas)"
        JOptionPane.showMessageDialog(
            None,
            u"Alterações realizadas:\n\n" + resumo,
            u"Nomes ajustados com sucesso",
            JOptionPane.PLAIN_MESSAGE
        )
    else:
        Notification(u"Nenhuma mudança necessária.")\
            .setIcon(UIManager.getIcon("OptionPane.informationIcon"))\
            .show()

# Executar
adjust_name_tags()

JavaScript

Última atualização: 2026-03-31

"use strict";

import { addResetCallback } from 'josm/context';
import { println } from 'josm/scriptingconsole';

// --- IMPORTS JAVA ---
const MainApplication = Java.type("org.openstreetmap.josm.gui.MainApplication");
const Notification = Java.type("org.openstreetmap.josm.gui.Notification");
const SequenceCommand = Java.type("org.openstreetmap.josm.command.SequenceCommand");
const ChangePropertyCommand = Java.type("org.openstreetmap.josm.command.ChangePropertyCommand");
const UndoRedoHandler = Java.type("org.openstreetmap.josm.data.UndoRedoHandler");
const UIManager = Java.type("javax.swing.UIManager");
const ArrayList = Java.type("java.util.ArrayList");

// Swing UI
const JDialog = Java.type("javax.swing.JDialog");
const JPanel = Java.type("javax.swing.JPanel");
const JTextField = Java.type("javax.swing.JTextField");
const JButton = Java.type("javax.swing.JButton");
const JLabel = Java.type("javax.swing.JLabel");
const BoxLayout = Java.type("javax.swing.BoxLayout");
const FlowLayout = Java.type("java.awt.FlowLayout");
const BorderFactory = Java.type("javax.swing.BorderFactory");
const Box = Java.type("javax.swing.Box");
const Robot = Java.type("java.awt.Robot");
const KeyEvent = Java.type("java.awt.event.KeyEvent");
const SwingConstants = Java.type("javax.swing.SwingConstants");

const SwingUtilities  = Java.type("javax.swing.SwingUtilities");
const LayerChangeListener = Java.extend(
    Java.type("org.openstreetmap.josm.gui.layer.LayerManager$LayerChangeListener")
);
const WindowAdapter = Java.extend(Java.type("java.awt.event.WindowAdapter"));

// --- GLOBAL STORAGE ---
let voiceDialog    = null;
let layerListener  = null;

function formatarNome(text) {
    if (!text) return "";
    let cleanText = text.replace(/\s+/g, " ").trim();

    const ignoreWords = new Set(["da", "das", "de", "do", "dos", "e", "com", "em"]);

    const siglas = new Set([
        "br", "sp", "rj", "mg", "rs", "es", "df", "go", "sc", "pr",
        "to", "pi", "pa", "ce", "pe", "ap", "am", "ro", "rr", "ac",
        "ma", "pb", "rn", "ba", "se", "al", "mt", "ms",
        "onu", "ibge", "dnit", "der", "lt", "ld"
    ]);

    // Abreviações expandidas — aplicadas antes do Title Case
    const abreviacoes = {
        "av.":   "Avenida",
        "r.":    "Rua",
        "tv.":   "Travessa",
        "rod.":  "Rodovia",
        "est.":  "Estrada",
        "prof.": "Professor",
        "dr.":   "Doutor",
        "faz.":  "Fazenda"                 
    };

    // Correções de acentuação por busca sem acento
    const correcoes = {
        "conceicao": "Conceição", "sao": "São",    "jose": "José",
        "joao": "João",   "antonio": "Antônio", "vitoria": "Vitória",
        "praca": "Praça", "maria": "Maria",     "francisco": "Francisco",
        "luiz": "Luiz",   "luís": "Luís",       "aparecida": "Aparecida"
    };

    // 1. Expande abreviações antes de processar palavras
    for (const abrev in abreviacoes) {
        const regex = new RegExp("\\b" + abrev.replace(".", "\\.") + "\\s*", "gi");
        cleanText = cleanText.replace(regex, abreviacoes[abrev] + " ");
    }
    cleanText = cleanText.replace(/\s+/g, " ").trim();

    // 2. Processa palavra a palavra com Title Case
    function tratarPalavra(word, isFirst) {
        const original = word.trim();
        if (!original) return "";
        const lower = original.toLowerCase();
        const semAcento = lower.normalize("NFD").replace(/[\u0300-\u036f]/g, "");

        // Sigla: mantém maiúscula ou detecta padrão tipo BR-101
        const limpo = semAcento.replace(/-/g, "").replace(/_/g, "");
        if (siglas.has(limpo) || /^[a-z]{2,}[-\d]+$/i.test(limpo)) {
            return original.toUpperCase();
        }

        // Correção de acentuação conhecida
        if (correcoes[semAcento]) return correcoes[semAcento];

        // Palavra ignorada (artigo/preposição) — exceto primeira
        if (ignoreWords.has(lower) && !isFirst) return lower;

        // Hífen: trata cada parte recursivamente
        if (original.includes("-")) {
            return original.split("-")
                .map((p, idx) => tratarPalavra(p, idx === 0 && isFirst))
                .join("-");
        }

        return lower.charAt(0).toUpperCase() + lower.slice(1);
    }

    return cleanText.split(/\s+/).map((w, i) => tratarPalavra(w, i === 0)).join(" ");
}

function mostrarInterfaceVoz() {

    voiceDialog = new JDialog(MainApplication.getMainFrame(), "Correção texto", false);
    const mainPanel = new JPanel();
    mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
    mainPanel.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));

    // --- SEÇÃO LOTE ---
    const painelLote = new JPanel(new FlowLayout(FlowLayout.CENTER));
    painelLote.setBorder(BorderFactory.createTitledBorder("Ações em Lote"));
    const btnCorrigirSelecao = new JButton("Corrigir Selecionados");
    btnCorrigirSelecao.addActionListener(() => {
        const layer = MainApplication.getLayerManager().getEditLayer();
        if (!layer) { 
            new Notification("Nenhuma camada de edição ativa.")
                .setIcon(UIManager.getIcon("OptionPane.errorIcon")).show(); 
            return; 
        }
        const selection = layer.data.getSelected();
        if (selection.isEmpty()) {
            new Notification("Selecione objetos no mapa primeiro.")
                .setIcon(UIManager.getIcon("OptionPane.warningIcon")).show();
            return;
        }

        const tagsAlvo = new Set(["name", "alt_name", "old_name", "official_name", "loc_name", "reg_name"]);
        const commands = new ArrayList();
        const alteracoes = [];
        const it = selection.iterator();
        while (it.hasNext()) {
            const obj = it.next();
            const keys = obj.getKeys();
            for (const entry of keys.entrySet()) {
                const key   = String(entry.getKey());
                const value = String(entry.getValue());
                if ((tagsAlvo.has(key) || key.startsWith("name:")) && value) {
                    const novo = formatarNome(value);
                    if (novo !== value) {
                        alteracoes.push(value + " → " + novo);
                        println("Corrigido [{0}]: {1} -> {2}", key, value, novo);
                        commands.add(new ChangePropertyCommand(obj, key, novo));
                    }
                }
            }
        }
        if (!commands.isEmpty()) {
            UndoRedoHandler.getInstance().add(new SequenceCommand("Correção Lote", commands));
            let resumo = alteracoes.join("\n");
            if (resumo.length > 300) resumo = resumo.substring(0, 300) + "\n...(mais alterações)";
            new Notification("Sucesso: " + commands.size() + " tag(s) corrigida(s).\n" + resumo)
                .setIcon(UIManager.getIcon("OptionPane.informationIcon")).show();
        } else {
            new Notification("Tudo OK: Nada a corrigir.")
                .setIcon(UIManager.getIcon("OptionPane.informationIcon")).show();
        }
    });
    painelLote.add(btnCorrigirSelecao);

    // --- SEÇÃO INDIVIDUAL ---
    const painelIndividual = new JPanel();
    painelIndividual.setLayout(new BoxLayout(painelIndividual, BoxLayout.Y_AXIS));
    painelIndividual.setBorder(BorderFactory.createTitledBorder("Entrada por Voz"));

    const btnVoz = new JButton("🎤 Ativar Ditado (Win+H)");
    const campoTexto = new JTextField(25);
    campoTexto.setFont(campoTexto.getFont().deriveFont(16.0));
    campoTexto.setHorizontalAlignment(SwingConstants.CENTER);

    btnVoz.addActionListener(() => {
        campoTexto.requestFocusInWindow();
        try {
            const robot = new Robot();
            robot.keyPress(KeyEvent.VK_WINDOWS);
            robot.keyPress(KeyEvent.VK_H);
            robot.keyRelease(KeyEvent.VK_H);
            robot.keyRelease(KeyEvent.VK_WINDOWS);
        } catch (e) { println("Erro Voz: {0}", e); }
    });

    // Enter no campo de texto dispara a mesma ação do botão Aplicar
    const ActionListener = Java.extend(Java.type("java.awt.event.ActionListener"));
    const aplicarDitado = new ActionListener({ actionPerformed: function() {
        const layer = MainApplication.getLayerManager().getEditLayer();
        if (!layer) {
            new Notification("Erro: Sem camada ativa!")
                .setIcon(UIManager.getIcon("OptionPane.errorIcon")).show();
            return;
        }
        const selection = layer.data.getSelected();
        if (selection.isEmpty()) {
            new Notification("Selecione um objeto no mapa.")
                .setIcon(UIManager.getIcon("OptionPane.warningIcon")).show();
            return;
        }
        const valorOriginal = campoTexto.getText();
        if (!valorOriginal.trim()) return;
        const nomeFinal = formatarNome(valorOriginal);
        const commands = new ArrayList();
        const it = selection.iterator();
        while (it.hasNext()) {
            commands.add(new ChangePropertyCommand(it.next(), "name", nomeFinal));
        }
        UndoRedoHandler.getInstance().add(new SequenceCommand("Voz: " + nomeFinal, commands));
        println("Aplicado via Voz: {0}", nomeFinal);
        campoTexto.setText("");
        campoTexto.requestFocusInWindow();
    }});
    campoTexto.addActionListener(aplicarDitado); // Enter no campo

    const btnAplicar = new JButton("Aplicar Ditado", UIManager.getIcon("OptionPane.yesIcon"));
    btnAplicar.addActionListener(aplicarDitado); // botão reutiliza o mesmo listener

    const pMic = new JPanel(new FlowLayout(FlowLayout.CENTER));
    pMic.add(btnVoz);
    const pApp = new JPanel(new FlowLayout(FlowLayout.CENTER));
    pApp.add(btnAplicar);

    painelIndividual.add(pMic);
    painelIndividual.add(campoTexto);
    painelIndividual.add(pApp);

    mainPanel.add(painelLote);
    mainPanel.add(Box.createVerticalStrut(10));
    mainPanel.add(painelIndividual);

    voiceDialog.add(mainPanel);
    voiceDialog.pack();
    voiceDialog.setLocationRelativeTo(MainApplication.getMainFrame());

    // Fecha ao remover a camada
    const sourceDs = _layer.data;
    layerListener = new LayerChangeListener({
        layerAdded:        function(_e) {},
        layerOrderChanged: function(_e) {},
        layerRemoving:     function(e) {
            const removed = e.getRemovedLayer();
            if (removed && removed.data && removed.data === sourceDs) {
                SwingUtilities.invokeLater(function() {
                    MainApplication.getLayerManager().removeLayerChangeListener(layerListener);
                    layerListener = null;
                    if (voiceDialog) { voiceDialog.dispose(); voiceDialog = null; }
                    new Notification("Camada removida. Diálogo fechado.")
                        .setIcon(UIManager.getIcon("OptionPane.warningIcon")).show();
                });
            }
        }
    });
    MainApplication.getLayerManager().addLayerChangeListener(layerListener);

    // Remove layerListener ao fechar o diálogo pelo X
    voiceDialog.addWindowListener(new WindowAdapter({ windowClosing: function() {
        if (layerListener) {
            MainApplication.getLayerManager().removeLayerChangeListener(layerListener);
            layerListener = null;
        }
    }}));

    voiceDialog.setVisible(true);
}

addResetCallback(function() {
    if (layerListener) {
        try { MainApplication.getLayerManager().removeLayerChangeListener(layerListener); } catch(e) {}
        layerListener = null;
    }
    if (voiceDialog) { voiceDialog.dispose(); voiceDialog = null; }
});

const _layer = MainApplication.getLayerManager().getEditLayer();
if (!_layer || !_layer.data) {
    new Notification("Nenhuma camada de edição ativa.")
        .setIcon(UIManager.getIcon("OptionPane.errorIcon")).show();
} else {
    mostrarInterfaceVoz();
}