Em uma das minhas tarefas do dia a dia, me deparei com esse problema: Como organizar uma base de dados de logradouros(endereços) ?Como eu poderia fazer isso de maneira prática e utilizando ferramentas já disponíveis?
Foi então que resolver usar o PHP e o LibreOffice Calc.
Contexto
Existe um S.I (ERP+CRM) onde é feito a gerência de todos os clientes. Nesse sistema todas as informações do cadastro de pessoa física/jurídica são utilizadas em outras partes do mesmo sistema. O módulo de CRM desse sistema utiliza, em uma de suas funcionalidades, os dados de endereço (cidade, bairro, logradouro) para posicionar o cliente em um mapa.
Hoje tenho acesso ao BD do sistema mas não tenho permissão de escrita. Preciso corrigir os problemas, enviar por ticket para o suporte do sistema e um arquivo CSV para eles fazerem as alterações no BD.
Problemas
Os logradouros cadastrados estão fora do padrão utilizado no mapa onde precisam ser exibidos, com isso é impossível posicionar o cliente no mapa.
Essa é uma lista dos itens que serão corrigidos:
- Os logradouros que se referem a mesma rua precisam ter a mesma grafia;
- Abreviações no nome do logradouro;
- Na grafia dos logradouros que tem números, precisam estar por extenso;
- Logradouros que tem a numeração de início e fim no nome;
- Logradouros com números Romanos;
Solução desenvolvida
No primeiro momento, conversando com a equipe do Comercial, me deram a ideia de utilizar o LibreOffice Calc para organizar os dados e fazer as correções.
Obtendo os dados, organizando e fazendo as primeiras correções
Utilizando o LibreOffice Calc:
Obtive os dados acessando o BD PostgreSQL do sistema e executando um SQL. Copiei os resultados para o LibreOffice Calc.
Dei nome as colunas facilitar a identificação e manipulação, ficou assim:
ID | LOGRADOURO | CODBAIRRO | CEP | CODCIDADE |
Dar nome as colunas me ajudou na hora de usar a opção Classificar do Calc. Selecionei toda área da tabela onde estava os dados, dentro da opção CLASSIFICAR eu selecionei a coluna LOGRADOURO na opção Chave de classificação 1.
Ainda no Calc, utilizando a opção Localizar e substituir alterei todos os registro que se enquadra nas condições:
TERMO | SUBSTITUÍDO POR |
R. | Rua |
R+ESPAÇO | Rua |
Tv. +ESPAÇO | Travessa |
RUA+ESPAÇO | Rua |
Av+ESPAÇO | Avenida |
Av.+ESPAÇO | Avenida |
Cel.+ESPAÇO | Coronel |
Dr.+ESPAÇO | Doutor |
Gen.+ESPAÇO | General |
Brig.+ESPAÇO | Brigadeiro |
Pre.+ESPAÇO | Presidente |
Obs: Em alguns casos, existe discordância se o logradouro é Rua, Avenida ou Travessa. Isso teve que ser corrigido também.
Utilizando PHP:
Depois de fazer todas as correções manuais comecei a analisar os problemas para identificar quais seriam possíveis de serem resolvidos usando programação em tempo hábil.
O resultado do código desenvolvido está abaixo:
<?php
//ativando os erros
ini_set(‘display_errors’, ‘On’);
//Exibindo todos os erros
error_reporting(E_ALL);
$caminho_do_csv = '/var/www/html/lista-enderecos-mk.csv';
//O parâmetro FILE_TEXT especifica que o arquivo é retornado na codificação UTF-8.
$array_csv = file($caminho_do_csv, FILE_TEXT);
$map_csv = array_map('str_getcsv', $array_csv);
////////// PROBLEMAS PARA RESOLVER
//(Feito) 1- Encontrar um padrão e tudo que estiver a direita desse padrão deve ser apagado. Ex: numeração de inicio e fim no nome da rua.
//(Feito) 2- Retirar os numeros do nome do logradouro. Geralmente os numeros errados estão no final do nome.
//Função para exibir os dados de um mapa de array
// @return Sem terno
function exibe_mapa(Array $mapa_de_array)
{
if($mapa_de_array != NULL)
{
foreach ($mapa_de_array as $key => $valor)
{
print("Posição do Array exteno: ".$key."<br/>");
print("------ID: ".$valor[0]."<br/>");
print("------Logradouro: ".$valor[1]."<br/>");
print("------CODBAIRRO: ".$valor[2]."<br/>");
print("------CEP: ".$valor[3]."<br/>");
print("------CODCIDADE: ".$valor[4]."<br/>");
print('---------------------------------------------------------');
print("<br/>");
};
};
};
//Função para encontrar um padrão de texto em um mapa de array
// @return Sem terno
function encontrar_padrao(String $padrao, Array $mapa_de_array)
{
//percorrer o array para achar o padrão, se for encontrato, o texto é destacado:
//<font color='red'> texto </font>
$qtd_encontrada=0;
foreach ($mapa_de_array as $key => $valor) {
print("Posição do Array exteno: ".$key."<br/>");
print("------ID: ".$valor[0]."<br/>");
if(stripos($valor[1],$padrao) !== false){
print("------Logradouro: <font color='red'>".$valor[1]."</font><br/>");
$qtd_encontrada=$qtd_encontrada+1;
}else{
print("------Logradouro: ".$valor[1]."<br/>");
};
print('---------------------------------------------------------');
print("<br/>");
};
echo 'Total de ocorrências do padrão: '.$qtd_encontrada;
};
//Essa função contem o array com as strings que devem ser desconsideradas na busca por algum tipo de padrão de string.
// @return Retorna 1 se a string passado por parâmetro estever no array e 0 para caso contrário.
function padrao_desconsiderado(String $string)
{
//Array com os padrões que devem ser desconsiderados
$desconsiderar_padrao = array("ms-","MS-","Ms-","Rua ");
foreach($desconsiderar_padrao as $valor)
{
//A pergunta feita no IF é: Algum dos padrões que estão no array coincide com a string passada por parâmetro?
//Em outras palavras: $valor C $string || $valor esta CONTIDO em $string?
if(stripos($string,$valor) !== false){
return 1;
break;
};
};
return 0;
};
//Salvando em um arquivo CSV
// @return Sem terno
function salvando_no_arq_csv(Array $mapa_de_array)
{
//O primeiro parâmetro é o arquivo.csv que eu já criei e dei permissão 777 nele.
$fp = fopen('file.csv', 'w+');
foreach ($mapa_de_array as $key => $valor)
{
fputcsv($fp, $valor);
};
fclose($fp);
};
//Solução do problema 2
// @return Retorna o mapa de Array com os campos editados
function problema2(String $padrao, Array $mapa_de_array)
{
//percorrer o Array para achar o padrão.
//Depois eu edito a posição do array onde foi achado o padrão e salvo o novo texto editado;
$novo_mapa_de_array = $mapa_de_array;
foreach ($mapa_de_array as $key => $valor) {
if(stripos($valor[1],$padrao) !== false){
//posição onde foi encontrado o padrão
$posicao = stripos($valor[1],$padrao);
//Copiando o o valor(Array) que
$array_temp = $novo_mapa_de_array[$key];
$array_temp[1] = substr($array_temp[1],0,$posicao);
$novo_mapa_de_array[$key] = $array_temp;
};
};
return $novo_mapa_de_array;
};
//Função para encontrar um padrão que atende a expresão regular passada por parâmetro
// @return Retorna um mapa de Array com o texto corrigido
function problema3(String $expressao, Array $mapa_de_array)
{
//Variável que salva temporáriamente um mapa de array com os padrões encontrados;
$matches;
// Novo Array que será retornado contendo o texto editado
$novo_mapa_de_array = $mapa_de_array;
//percorrer o Array para achar o padrão, se for encontrato o padrão é excluido;
foreach ($mapa_de_array as $key => $valor)
{
//IMPORTANTE: a expressão precisa estár entre barras -> EX: /[0-9]/
if(preg_match('/'.$expressao.'/',$valor[1]))
{
if(padrao_desconsiderado($valor[1]) == 0){
preg_match('/'.$expressao.'/',$valor[1],$matches, PREG_OFFSET_CAPTURE);
$temp = $matches[0];
$array_temp = $novo_mapa_de_array[$key];
$array_temp[1] = substr($valor[1],0,$temp[1]);
$novo_mapa_de_array[$key] = $array_temp;
}else{
print_r("Valor: ".$valor[1]."<br/>");
printf("Variável temp[0] padrão: ".$temp[0]."<br/>");
printf("Variável temp[1] posição: ".$temp[1]."<br/><br/>");
}
}
};
return $novo_array_de_mapa;
};
//Resolve problema 2
//padrão para achar as ruas que tem a numeração de inicio e fim no nome
$padrao = ' - ';
//Resolve Problema 3
//Para achar numeros que estão no final do nome da rua
$expressao_problema_3 = '[0-9]{2,5}$';
$corrigido = problema2($padrao, $map_csv);
$corrigido2 = problema3($expressao_problema_3,$corrigido);
salvando_no_arq_csv($corrigido2);
?>