Pergunta

Problema:Eu tenho um campo de endereço de um banco de dados Access que foi convertido para Sql Server 2005.Este campo tem tudo em um só campo.Preciso analisar as seções individuais do endereço em seus campos apropriados em uma tabela normalizada.Preciso fazer isso para aproximadamente 4.000 registros e precisa ser repetível.

Premissas:

  1. Suponha um endereço nos EUA (por enquanto)

  2. suponha que a string de entrada às vezes conterá um destinatário (a pessoa a quem se dirige) e/ou um segundo endereço (ou seja,Suíte B)

  3. estados podem ser abreviados

  4. o código postal pode ser padrão de 5 dígitos ou zip+4

  5. há erros de digitação em alguns casos

ATUALIZAR:Em resposta às questões colocadas, os padrões não foram seguidos universalmente, preciso armazenar os valores individuais, não apenas o geocódigo e os erros significam erros de digitação (corrigidos acima)

Dados de amostra:

  • A.P.Croll & Son 2299 Lewes-Georgetown Hwy, Georgetown, DE 19947

  • 11522 Shawnee Road, Greenwood DE 19950

  • 144 Kings Highway, SW.Dover, DE 19901

  • Const. IntegradaServiços 2 Penns Way Suite 405 New Castle, DE 19720

  • Humes Realty 33 Bridle Ridge Court, Lewes, DE 19958

  • Escavação Nichols 2742 Pulaski Hwy Newark, DE 19711

  • 2284 Bryn Zion Road, Smyrna, DE 19904

  • VEI Dover Crossroads, LLC 1500 Serpentine Road, Suíte 100 Baltimore MD 21

  • 580 North Dupont Highway Dover, DE 19901

  • POCaixa 778 Dover, DE 19903

Foi útil?

Solução

Eu trabalhei muito nesse tipo de análise.Como existem erros, você não obterá 100% de precisão, mas há algumas coisas que você pode fazer para chegar até lá e, em seguida, fazer um teste visual de BS.Esta é a maneira geral de fazer isso.Não é código, porque é bastante acadêmico escrevê-lo, não há estranheza, apenas muito manuseio de strings.

(Agora que você postou alguns dados de amostra, fiz algumas pequenas alterações)

  1. Trabalhe para trás.Comece pelo CEP, que estará próximo ao final, e em um dos dois formatos conhecidos:XXXXX ou XXXXX-XXXX.Se isso não aparecer, você pode presumir que está na cidade, parte do estado, abaixo.
  2. A próxima coisa, antes do zip, será o estado, e estará no formato de duas letras ou em palavras.Você também sabe quais serão - há apenas 50 deles.Além disso, você pode soar as palavras para ajudar a compensar erros ortográficos.
  3. antes disso é a cidade, e é provavelmente na mesma linha do estado.Você poderia usar um banco de dados de código postal para verificar a cidade e o estado com base no CEP, ou pelo menos usá-lo como detector de BS.
  4. O endereço geralmente terá uma ou duas linhas.A segunda linha geralmente será o número do conjunto, se houver, mas também pode ser uma caixa postal.
  5. Será quase impossível detectar um nome na primeira ou na segunda linha, mas se não for prefixado com um número (ou se for prefixado com "attn:" ou "atenção para:", isso pode lhe dar uma dica como se é um nome ou uma linha de endereço.

Eu espero que isso ajude de algum jeito.

Outras dicas

Acho que terceirizar o problema é a melhor aposta:envie-o para o geocodificador do Google (ou Yahoo).O geocodificador retorna não apenas a lat/long (que não é de interesse aqui), mas também uma análise rica do endereço, com campos preenchidos que você não enviou (incluindo ZIP+4 e condado).

Por exemplo, a análise de "1600 Amphitheatre Parkway, Mountain View, CA" resulta

{
  "name": "1600 Amphitheatre Parkway, Mountain View, CA, USA",
  "Status": {
    "code": 200,
    "request": "geocode"
  },
  "Placemark": [
    {
      "address": "1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA",
      "AddressDetails": {
        "Country": {
          "CountryNameCode": "US",
          "AdministrativeArea": {
            "AdministrativeAreaName": "CA",
            "SubAdministrativeArea": {
              "SubAdministrativeAreaName": "Santa Clara",
              "Locality": {
                "LocalityName": "Mountain View",
                "Thoroughfare": {
                  "ThoroughfareName": "1600 Amphitheatre Pkwy"
                },
                "PostalCode": {
                  "PostalCodeNumber": "94043"
                }
              }
            }
          }
        },
        "Accuracy": 8
      },
      "Point": {
        "coordinates": [-122.083739, 37.423021, 0]
      }
    }
  ]
}

Agora isso é analisável!

O autor da postagem original provavelmente já mudou há muito tempo, mas tentei portar o Perl Geo::Endereço:EUA módulo usado por geocoder.us para C#, joguei-o no CodePlex e acho que as pessoas que se depararem com essa questão no futuro poderão considerá-la útil:

Analisador de endereços nos EUA

Na página inicial do projeto procuro falar sobre suas (muito reais) limitações.Como não é apoiado pelo banco de dados de endereços válidos do USPS, a análise pode ser ambígua e não pode confirmar nem negar a validade de um determinado endereço.Ele pode apenas tentar extrair dados da string.

Destina-se ao caso em que você precisa obter um conjunto de dados principalmente nos campos corretos ou deseja fornecer um atalho para entrada de dados (permitindo que os usuários colem um endereço em uma caixa de texto em vez de navegar entre vários campos).Isso é não destinado a verificar a capacidade de entrega de um endereço.

Ele não tenta analisar nada acima da linha da rua, mas provavelmente seria possível mexer no regex para obter algo razoavelmente próximo - eu provavelmente interromperia no número da casa.

Eu fiz isso no passado.

Faça isso manualmente (crie uma interface agradável que ajude o usuário a fazer isso rapidamente) ou automatize-o e verifique um banco de dados de endereços recente (você precisa comprá-lo) e lide manualmente com os erros.

O manuseio manual levará cerca de 10 segundos cada, o que significa que você pode fazer 3600/10 = 360 por hora, então 4000 devem levar aproximadamente 11 a 12 horas.Isso lhe dará uma alta taxa de precisão.

Para automação, você precisar um banco de dados de endereços recente dos EUA e ajuste suas regras em relação a isso.Eu sugiro não se interessar pelo regex (difícil de manter a longo prazo, tantas exceções).Vá para 90% de correspondência com o banco de dados, faça o resto manualmente.

Obtenha uma cópia dos Padrões de Endereçamento Postal (USPS) em http://pe.usps.gov/cpim/ftp/pubs/Pub28/pub28.pdf e observe que tem mais de 130 páginas.Regexes para implementar isso seriam uma loucura.

Para endereços internacionais, todas as apostas estão canceladas.Os trabalhadores baseados nos EUA não seriam capazes de validar.

Como alternativa, use um serviço de dados.Contudo, não tenho recomendações.

Além disso:quando você enviar o material pelo correio (é para isso que serve, certo?) certifique-se de colocar "correção de endereço solicitada" no envelope (no lugar certo) e atualizar o banco de dados.(Fizemos uma interface simples para o recepcionista fazer isso;a pessoa que realmente classifica a correspondência)

Finalmente, depois de limpar os dados, procure por duplicatas.

Após o conselho aqui, desenvolvi a seguinte função em VB que cria dados utilizáveis ​​​​passáveis, embora nem sempre perfeitos (se o nome da empresa e uma linha de suíte forem fornecidos, ela combina a suíte e a cidade).Sinta-se à vontade para comentar/refatorar/gritar comigo por quebrar uma de minhas próprias regras, etc.:

Public Function parseAddress(ByVal input As String) As Collection
    input = input.Replace(",", "")
    input = input.Replace("  ", " ")
    Dim splitString() As String = Split(input)
    Dim streetMarker() As String = New String() {"street", "st", "st.", "avenue", "ave", "ave.", "blvd", "blvd.", "highway", "hwy", "hwy.", "box", "road", "rd", "rd.", "lane", "ln", "ln.", "circle", "circ", "circ.", "court", "ct", "ct."}
    Dim address1 As String
    Dim address2 As String = ""
    Dim city As String
    Dim state As String
    Dim zip As String
    Dim streetMarkerIndex As Integer

    zip = splitString(splitString.Length - 1).ToString()
    state = splitString(splitString.Length - 2).ToString()
    streetMarkerIndex = getLastIndexOf(splitString, streetMarker) + 1
    Dim sb As New StringBuilder

    For counter As Integer = streetMarkerIndex To splitString.Length - 3
        sb.Append(splitString(counter) + " ")
    Next counter
    city = RTrim(sb.ToString())
    Dim addressIndex As Integer = 0

    For counter As Integer = 0 To streetMarkerIndex
        If IsNumeric(splitString(counter)) _
            Or splitString(counter).ToString.ToLower = "po" _
            Or splitString(counter).ToString().ToLower().Replace(".", "") = "po" Then
                addressIndex = counter
            Exit For
        End If
    Next counter

    sb = New StringBuilder
    For counter As Integer = addressIndex To streetMarkerIndex - 1
        sb.Append(splitString(counter) + " ")
    Next counter

    address1 = RTrim(sb.ToString())

    sb = New StringBuilder

    If addressIndex = 0 Then
        If splitString(splitString.Length - 2).ToString() <> splitString(streetMarkerIndex + 1) Then
            For counter As Integer = streetMarkerIndex To splitString.Length - 2
                sb.Append(splitString(counter) + " ")
            Next counter
        End If
    Else
        For counter As Integer = 0 To addressIndex - 1
            sb.Append(splitString(counter) + " ")
        Next counter
    End If
    address2 = RTrim(sb.ToString())

    Dim output As New Collection
    output.Add(address1, "Address1")
    output.Add(address2, "Address2")
    output.Add(city, "City")
    output.Add(state, "State")
    output.Add(zip, "Zip")
    Return output
End Function

Private Function getLastIndexOf(ByVal sArray As String(), ByVal checkArray As String()) As Integer
    Dim sourceIndex As Integer = 0
    Dim outputIndex As Integer = 0
    For Each item As String In checkArray
        For Each source As String In sArray
            If source.ToLower = item.ToLower Then
                outputIndex = sourceIndex
                If item.ToLower = "box" Then
                    outputIndex = outputIndex + 1
                End If
            End If
            sourceIndex = sourceIndex + 1
        Next
        sourceIndex = 0
    Next
    Return outputIndex
End Function

Passando o parseAddress função “A.P.Croll & Son 2299 Lewes-Georgetown Hwy, Georgetown, DE 19947" retorna:

2299 Lewes-Georgetown Hwy
A. P. Croll & Son  
Georgetown
DE
19947

Trabalho no domínio de processamento de endereços há cerca de 5 anos e realmente não existe solução mágica.A solução correta vai depender do valor dos dados.Se não for muito valioso, passe-o por um analisador, como sugerem as outras respostas.Se for algo valioso, você definitivamente precisará que um humano avalie/corrija todos os resultados do analisador.Se você está procurando uma solução totalmente automatizada e repetível, provavelmente deseja falar com um fornecedor de correção de endereço como Group1 ou Trillium.

SmartyStreets possui um novo recurso que extrai endereços de strings de entrada arbitrárias.(Observação:Eu não trabalho no SmartyStreets.)

Ele extraiu com sucesso todos os endereços do exemplo de entrada fornecido na pergunta acima.(A propósito, apenas 9 desses 10 endereços são válidos.)

Aqui estão alguns dos resultados:enter image description here

E aqui está a saída formatada em CSV dessa mesma solicitação:

ID,Start,End,Segment,Verified,Candidate,Firm,FirstLine,SecondLine,LastLine,City,State,ZIPCode,County,DpvFootnotes,DeliveryPointBarcode,Active,Vacant,CMRA,MatchCode,Latitude,Longitude,Precision,RDI,RecordType,BuildingDefaultIndicator,CongressionalDistrict,Footnotes
1,32,79,"2299 Lewes-Georgetown Hwy, Georgetown, DE 19947",N,,,,,,,,,,,,,,,,,,,,,,
2,81,119,"11522 Shawnee Road, Greenwood DE 19950",Y,0,,11522 Shawnee Rd,,Greenwood DE 19950-5209,Greenwood,DE,19950,Sussex,AABB,199505209226,Y,N,N,Y,38.82865,-75.54907,Zip9,Residential,S,,AL,N#
3,121,160,"144 Kings Highway, S.W. Dover, DE 19901",Y,0,,144 Kings Hwy,,Dover DE 19901-7308,Dover,DE,19901,Kent,AABB,199017308444,Y,N,N,Y,39.16081,-75.52377,Zip9,Commercial,S,,AL,L#
4,190,232,"2 Penns Way Suite 405 New Castle, DE 19720",Y,0,,2 Penns Way Ste 405,,New Castle DE 19720-2407,New Castle,DE,19720,New Castle,AABB,197202407053,Y,N,N,Y,39.68332,-75.61043,Zip9,Commercial,H,,AL,N#
5,247,285,"33 Bridle Ridge Court, Lewes, DE 19958",Y,0,,33 Bridle Ridge Cir,,Lewes DE 19958-8961,Lewes,DE,19958,Sussex,AABB,199588961338,Y,N,N,Y,38.72749,-75.17055,Zip7,Residential,S,,AL,L#
6,306,339,"2742 Pulaski Hwy Newark, DE 19711",Y,0,,2742 Pulaski Hwy,,Newark DE 19702-3911,Newark,DE,19702,New Castle,AABB,197023911421,Y,N,N,Y,39.60328,-75.75869,Zip9,Commercial,S,,AL,A#
7,341,378,"2284 Bryn Zion Road, Smyrna, DE 19904",Y,0,,2284 Bryn Zion Rd,,Smyrna DE 19977-3895,Smyrna,DE,19977,Kent,AABB,199773895840,Y,N,N,Y,39.23937,-75.64065,Zip7,Residential,S,,AL,A#N#
8,406,450,"1500 Serpentine Road, Suite 100 Baltimore MD",Y,0,,1500 Serpentine Rd Ste 100,,Baltimore MD 21209-2034,Baltimore,MD,21209,Baltimore,AABB,212092034250,Y,N,N,Y,39.38194,-76.65856,Zip9,Commercial,H,,03,N#
9,455,495,"580 North Dupont Highway Dover, DE 19901",Y,0,,580 N DuPont Hwy,,Dover DE 19901-3961,Dover,DE,19901,Kent,AABB,199013961803,Y,N,N,Y,39.17576,-75.5241,Zip9,Commercial,S,,AL,N#
10,497,525,"P.O. Box 778 Dover, DE 19903",Y,0,,PO Box 778,,Dover DE 19903-0778,Dover,DE,19903,Kent,AABB,199030778781,Y,N,N,Y,39.20946,-75.57012,Zip5,Residential,P,,AL,

Fui o desenvolvedor que escreveu originalmente o serviço.O algoritmo que implementamos é um pouco diferente de qualquer resposta específica aqui, mas cada endereço extraído é verificado na API de pesquisa de endereço, para que você possa ter certeza se é válido ou não.Cada resultado verificado é garantido, mas sabemos que os outros resultados não serão perfeitos porque, como foi feito abundantemente claro neste tópico, os endereços são imprevisíveis, às vezes até mesmo para humanos.

Isso não resolverá seu problema, mas se você precisou apenas de dados Lat/Long para esses endereços, a API do Google Maps analisará muito bem os endereços não formatados.

Boa sugestão: alternativamente, você pode executar uma solicitação CURL para cada endereço ao Google Maps e ele retornará o endereço formatado corretamente.A partir disso, você pode regex o quanto quiser.

+1 em James A.A solução sugerida por Rosen funcionou bem para mim, no entanto, para os completistas, este site é uma leitura fascinante e a melhor tentativa que já vi de documentar endereços em todo o mundo: http://www.columbia.edu/kermit/postal.html

Existe algum padrão na forma como os endereços são registrados?Por exemplo:

  1. Sempre há vírgulas ou novas linhas separando a rua 1 da rua 2 da cidade do estado do CEP?
  2. Os tipos de endereço (estrada, rua, avenida, etc.) são sempre especificados?sempre abreviado?Um pouco de cada?
  3. Defina "erro".

Minha resposta geral é uma série de Expressões Regulares, embora a complexidade disso dependa da resposta.E se não houver nenhuma consistência, então você só conseguirá obter sucesso parcial com um Regex (ou seja:filtrando código postal e estado) e terá que fazer o resto manualmente (ou pelo menos passar pelo resto com muito cuidado para ter certeza de identificar os erros).

Outra solicitação de dados de amostra.

Como foi mencionado, eu trabalharia de trás para frente a partir do zip.

Depois de ter um zip, eu consultaria um banco de dados zip, armazenaria os resultados e os removeria e o zip da string.

Isso vai deixar você com uma bagunça de endereço.A MAIORIA dos endereços (todos?) Começarão com um número, então encontre a primeira ocorrência de um número na string restante e pegue tudo, desde ele até o (novo) final da string.Esse será o seu endereço.Qualquer coisa à esquerda desse número provavelmente é um destinatário.

Agora você deve ter Cidade, Estado e CEP armazenados em uma tabela e possivelmente duas strings, destinatário e endereço.Para o endereço, verifique a existência de "suíte" ou "apt". etc.e divida isso em dois valores (linhas de endereço 1 e 2).

Para o destinatário, eu apontaria e pegaria a última palavra dessa string como o sobrenome e colocaria o restante no campo do nome.Se não quiser fazer isso, você precisará verificar a saudação (Sr., Sra., Dr., etc.) no início e fazer algumas suposições com base no número de espaços sobre como o nome é decidir.

Não acho que haja como analisar com 100% de precisão.

Tentar www.address-parser.com.Usamos o serviço web deles, que você pode testar online

Com base nos dados da amostra:

  1. Eu começaria no final da string.Analise um código postal (qualquer formato).Leia do final ao primeiro espaço.Se nenhum CEP foi encontrado Erro.

  2. Corte o final para espaços e caracteres especiais (vírgulas)

  3. Em seguida, vá para o Estado e use novamente o Espaço como delimitador.Talvez use uma lista de pesquisa para validar códigos de estado de 2 letras e nomes completos de estado.Se nenhum estado válido for encontrado, erro.

  4. Apare espaços e vírgulas do final novamente.

  5. A cidade fica complicada, na verdade eu usaria uma vírgula aqui, correndo o risco de obter muitos dados na cidade.Procure a vírgula ou o início da linha.

  6. Se você ainda tiver caracteres na string, coloque tudo isso em um campo de endereço.

Isso não é perfeito, mas deve ser um bom ponto de partida.

Se forem dados inseridos por humanos, você gastará muito tempo tentando codificar as exceções.

Tentar:

  1. Expressão regular para extrair o CEP

  2. Pesquisa de código postal (por meio do banco de dados governamental apropriado) para obter o endereço correto

  3. Peça a um estagiário para verificar manualmente se os novos dados correspondem aos antigos

Isso não resolverá seu problema, mas se você precisar apenas de dados de latitude/longitude para esses endereços, a API do Google Maps analisará muito bem os endereços não formatados.

RecogniContact é um objeto COM do Windows que analisa endereços dos EUA e da Europa.Você pode tentar imediatamentehttp://www.loquisoft.com/index.php?page=8

Você pode querer checar isso!! http://jgeocoder.sourceforge.net/parser.htmlCaiu como uma luva para mim.

Este tipo de problema é difícil de resolver devido às ambiguidades subjacentes nos dados.

Aqui está uma solução baseada em Perl que define uma árvore gramatical descendente recursiva baseada em expressões regulares para analisar muitas combinações válidas de endereços: http://search.cpan.org/~kimryan/Lingua-EN-AddressParse-1.20/lib/Lingua/EN/AddressParse.pm .Isso inclui subpropriedades dentro de um endereço como:12 1st Avenue N Suite # 2 em algum lugar CA 12345 EUA

É similar à http://search.cpan.org/~timb/Geo-StreetAddress-US-1.03/US.pm mencionado acima, mas também funciona para endereços que não são dos EUA, como Reino Unido, Austrália e Canadá.

Aqui está a saída para um dos seus endereços de exemplo.Observe que a seção do nome precisaria ser removida primeiro de "A.P.Croll & Son 2299 Lewes-Georgetown Hwy, Georgetown, DE 19947" para reduzi-lo para "2299 Lewes-Georgetown Hwy, Georgetown, DE 19947".Isso é facilmente conseguido removendo todos os dados até o primeiro número encontrado na string.

Non matching part       ''
Error                   '0'
Error descriptions      ''
Case all                '2299 Lewes-Georgetown Hwy Georgetown DE 19947'
COMPONENTS              ''
country                 ''
po_box_type             ''
post_box                ''
post_code               '19947'
pre_cursor              ''
property_identifier     '2299'
property_name           ''
road_box                ''
street                  'Lewes-Georgetown'
street_direction        ''
street_type             'Hwy'
sub_property_identifier ''
subcountry              'DE'
suburb                  'Georgetown'

Como há chance de erro no word, pense em usar o SOUNDEX combinado com o algoritmo LCS para comparar strings, isso vai ajudar muito!

usando a API do Google

$d=str_replace(" ", "+", $address_url);
$completeurl ="http://maps.googleapis.com/maps/api/geocode/xml?address=".$d."&sensor=true"; 
$phpobject = simplexml_load_file($completeurl);
print_r($phpobject);

Para desenvolvedores Ruby ou Rails, há uma bela joia disponível chamada endereço da Rua.Tenho usado isso em um dos meus projetos e ele faz o trabalho que preciso.

O único problema que tive foi sempre que um endereço estava neste formato P. O. Box 1410 Durham, NC 27702 retornou nulo e portanto tive que substituir "P.Ó.Box" com '' e depois disso foi possível analisá-lo.

Existem serviços de dados que, com um código postal, fornecem uma lista de nomes de ruas nesse código postal.

Use um regex para extrair Zip ou City State - encontre o correto ou, se ocorrer um erro, obtenha os dois.puxe a lista de ruas de um fonte de dados Corrija a cidade e o estado e depois o endereço.Depois de obter uma linha de endereço 1 válida, cidade, estado e CEP, você poderá fazer suposições na linha de endereço 2..3

Não sei COMO isso seria VIÁVEL, mas não vi isso mencionado, então pensei em prosseguir e sugerir o seguinte:

Se você estiver estritamente nos EUA...obtenha um enorme banco de dados de todos os códigos postais, estados, cidades e ruas.Agora procure por isso em seus endereços.Você pode validar o que encontrou testando se, digamos, a cidade que você encontrou existe no estado que você encontrou, ou verificando se a rua que você encontrou existe na cidade que você encontrou.Caso contrário, é provável que John não seja da rua de John, mas seja o nome do destinatário...Basicamente, obtenha o máximo de informações possível e compare seus endereços com elas.Um exemplo extremo seria obter UMA LISTA DE TODOS OS ENDEREÇOS NOS EUA DE A e então descobrir qual deles corresponde mais relevante a cada um dos seus endereços...

Existe uma porta javascript do pacote perl Geo::StreetAddress::US: https://github.com/hassansin/parse-address .É baseado em regex e funciona muito bem.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top