2012-05-29 3 views
6

Ich versuche, eine VBA-Funktion in Access zu schreiben, die Wörter in einem Adressfeld durch den Standard United States Postal Abbreviations ersetzt. Mir ist klar, dass dies niemals perfekt sein wird, aber ich möchte zumindest einfache Abkürzungen machen (ohne eine Adressformatierungssoftware kaufen zu müssen), , z.B.Verwenden von RegEx und Ersetzen zum Aktualisieren von Adressfeldern mit USPS-Abkürzungen in MS-Access

input  output 
------- ------------- 
North -> N 
Street -> ST 
Drive -> DR 
Lane -> LN 

Ich dachte über eine einfache Tabelle mit dem String und die Ersatzzeichenfolge zu speichern, und dann Schleife durch diese Tabelle/Cord-eine einfache Suche durchführen und ersetzen mit der Replace() Funktion, z.B. unter Verwendung der immediate window:

?Replace("123 North 3rd St", "North", "N", compare:=vbTextCompare) 
123 N 3rd St 

Jedoch kann dieses Verfahren möglicherweise zu Fehlern führen, z.B.

?Replace("123 Northampton St", "North", "N", compare:=vbTextCompare) 
123 Nampton St 

Meine ursprüngliche Strategie war es, eine Ersetzungstabelle mit regulären Ausdruck Muster und Ersatzzeichenfolgen zu erstellen, dann Schleife durch diese Tabelle eine genauere Suche und ersetzen zu tun.

pattern     abbrev 
-------------------  ------------ 
{pattern for North}  N 
{pattern for Street} ST 

Ich erkennen, dass RegEx Overkill hier sein könnte, zumal ich Schleife durch Adressfelder immer und immer wieder in einer Datenbank sein werde, aber denken Sie konnte nicht von einem einfacheren Weg, nur mit der Replace() Funktion (Update: siehe Antworten von @ mwolfe02 und @ Cylian und eine Hybridlösung).

In dem obigen Beispiel möchte ich nach den Wörtern North und Street suchen, wenn sie entweder als ein Wort in einer Zeichenfolge (also durch zwei weiße Leerzeichen getrennt) oder am Ende der Zeichenfolge oder Anfang von a existieren Zeichenfolge. Dies deckt die meisten Situationen ab, die eine Abkürzung rechtfertigen. z.B.

address      formatted 
----------------------  -------------------------- 
123 North 3rd St   -> 123 N 3RD ST 
123 ABC Street North  -> 123 ABC ST N 
North 3rd Street   -> N 3RD ST 
123 North Northampton St -> 123 N NORTHAMPTON ST 

Wie in diesen Beispielen möchte ich in der Folge alle Instanzen des Musters ersetzen. Ich konvertiere auch alles in Großbuchstaben (ich kann UCase() auf das Endergebnis kein Problem verwenden).

Weiß jemand von einem vorhandenen Modul, das so etwas tut? Kann jemand mit dem Mustervergleich wie in den obigen Beispielen helfen? Für zusätzliches Guthaben bin ich auch neugierig auf das Erstellen von Regeln in der Tabelle zum Formatieren von Post-Office-Boxen, z. B. , z.

address     formatted 
---------------------- -------------------------- 
P.O. Box 345   -> PO BOX 345 
PO Box 345    -> PO BOX 345 
Post Office Box 345 -> PO BOX 345 
PO. Box 345   -> PO BOX 345 
P. O. Box 345   -> PO BOX 345 

This stack overflow post ergibt sich folgendes Muster einige Postfächer zu erkennen "^ \ s * P.? \ S? O.? \ SB [Oo] [Xx]." (freilich nicht das dritte Beispiel oben). Wiederum bin ich nicht so gut mit Matching- und Ersatz-Sets vertraut, um herauszufinden, wie man diese präzisere Ersatzfunktion schreibt. Gibt es einen RegEx/Access-Experten, der helfen kann?

Antwort

0

Ich habe eine sehr einfache Referenztabelle ref_USPS_abbrev von der USPS Abkürzungsliste online. Hier sind die Einträge, die das Beispiel entsprechen ursprünglich gegeben:

WORD   ABBREV 
------------ ------------- 
NORTH   N 
STREET  ST 

Dann Antworten auf meinen ursprünglichen Beitrag enthält, habe ich zwei Hilfsfunktionen erstellt.

Von @Cylian:

' ----------------------------------------------------------------------' 
    ' Formats string containing P.O. Box to USPS Approved PO BOX format ' 
    ' ----------------------------------------------------------------------' 
    ' Requires Microsoft VBScript Regular Expressions 5.5 

    Public Function FormatPO(inputString As String) As String 

     Static rePO As Object 
     If rePO Is Nothing Then 
      Set rePO = CreateObject("vbscript.regexp") 
     With rePO 
     .Pattern = "\bP(?:[. ]+|ost +)?O(?:ff\.?(?:ice))" & _ 
        "?[. ]+B(?:ox|\.) +(\d+)\b" 
     .Global = True 
     .IgnoreCase = True 
     End With 
     End If 

     With rePO 
      If .Test(inputString) Then 
       FormatPO = .Replace(inputString, "PO BOX $1") 
      Else 
       FormatPO = inputString 
      End If 
     End With 
    End Function 

Und @ mwolfe02 die hervorragende Idee, mit:

' ----------------------------------------------------------------------' 
    ' Replaces whole word only with an abbreviation in address string  ' 
    ' ----------------------------------------------------------------------' 

    Public Function AddressReplace(AddressLine As String, _ 
        FullName As String, _ 
        Abbrev As String) 

    'Enclose address line in an opening and closing space, so that you 
    'can require an opening and closing space on each word you are trying 
    'to replace. Finish up with a trim to get rid of those temporary spaces. 

    AddressReplace = Trim(Replace(" " & AddressLine & " ", _ 
           " " & FullName & " ", _ 
           " " & Abbrev & " ")) 
    End Function 

Dann diese Hilfsfunktionen enthalten, schrieb ich diese Funktion:

' ----------------------------------------------------------------------' 
' Format address using abbreviations stored in table ref_USPS_abbrev ' 
' ----------------------------------------------------------------------' 
' Requires Microsoft DAO 3.6 Object Library 
' Table ref_USPS_abbrev has two fields: WORD (containing the word to match) 
' and ABBREV containing the desired abbreviated substitution. 
' United States Postal Services abbreviations are available at: 
' https://www.usps.com/ship/official-abbreviations.htm 

Public Function SubstituteUSPS(address As String) As String 

Static dba As DAO.Database 
Static rst_abbrev As DAO.Recordset 

    If IsNull(address) Then Exit Function 

    'Initialize the objects 

    If dba Is Nothing Then 
     Set dba = CurrentDb 
    End If 

    'Create the rst_abbrev recordset once from ref_USPS_abbrev. If additional 
    'entries are added to the source ref_USPS_abbrev table after the recordset 
    'is created, since it is an dbOpenTable (by default), the recordset will 
    'be updated dynamically. If you use dbOpenSnapshot it will not update 
    'dynamically. 

    If rst_abbrev Is Nothing Then 
     Set rst_abbrev = dba.OpenRecordset("ref_USPS_abbrev", _ 
              Type:=dbOpenTable) 
    End If 

    'Since rst_abbrev is a static object, in the event the function is called 
    'in succession (e.g. while looping through a recordset to update values), 
    'move to the first entry in the recordset each time the function is 
    'called. 

    rst_abbrev.MoveFirst 

    'Only call the FormatPO helper function if the address has the 
    'string "ox" in it.  

    If InStr(address, "ox") > 0 Then 
     address = FormatPO(address) 
    End If 

    'Loop through the recordset containing the abbreviations 
    'and use the AddressReplace helper function to substitute 
    'abbreviations for whole words only. 

    Do Until rst_abbrev.EOF 
     address = AddressReplace(address, rst_abbrev![WORD], _ 
           rst_abbrev![ABBREV]) 
     rst_abbrev.MoveNext 
    Loop 

    'Convert the address to upper case and trim white spaces and return result 
    'You can also add code here to trim out punctuation in the address, too. 

    SubstituteUSPS = Trim(UCase(address)) 

End Function 

zu Erstellen Sie die Tabelle ref_USPS_abbrev zum Testen:

Sub CreateUSPSTable() 

Dim dbs As Database 
Set dbs = CurrentDb 

With dbs 
    .Execute "CREATE TABLE ref_USPS_abbrev " _ 
     & "(WORD CHAR, ABBREV CHAR);" 
    .Execute " INSERT INTO ref_USPS_abbrev " _ 
     & "(WORD, ABBREV) VALUES " _ 
     & "('NORTH', 'N');" 
    .Execute " INSERT INTO ref_USPS_abbrev " _ 
     & "(WORD, ABBREV) VALUES " _ 
     & "('STREET', 'ST');" 
    .Close 
End With 
End Sub 

Schließlich testet diese Funktion von der immediate window:

CreateUSPSTable 
?SubstituteUSPS("Post Office Box 345 123 North Northampton Street") 
PO BOX 345 123 N NORTHAMPTON ST 

Ich bin kein Programmierer professionell, so würde ich Vorschläge willkommen meinen Code zur Reinigung noch weiter, aber jetzt diese Werke groß. Danke, alle.

Stack Overflow noch einmal FTW!

+0

Im Moment habe ich Probleme mit der '' SubstituteUSPS() '' Funktion beim Durchlaufen meiner Quellentabelle. Ich habe keine Probleme mit der Funktion, wenn sie alleine benutzt wird; aber es scheint nicht zu funktionieren, wenn es mit einem anderen Re-Cord-Set kombiniert wird. Ideen? – regulus

+0

Ich habe es herausgefunden. Nach jedem Durchlauf muss ich das statische Recordset ** rst_abbrev ** auf die erste Position zurücksetzen. Ich habe den Code aktualisiert. – regulus

5

diese Funktion Versuchen

Public Function FormatPO(inputString$) 
'This example uses **Microsoft VBScript Regular Expressions 5.5** 
Dim re As New RegExp, result$ 
With re 
    .Pattern = "\bP(?:[. ]+|ost +)?O(?:ff\.?(?:ice))?[. ]+B(?:ox|\.) +(\d+)\b" 
    .Global = True 
    .IgnoreCase = True 
    If .test(inputString) Then 
     FormatPO = .Replace(inputString, "PO BOX $1") 
    Else 
     MsgBox "Data doesn't matched!" 
    End If 
End With 

und als (von immediate window)

?FormatPO("P.O. Box 563") 

gibt Ergebnis

PO BOX 563 
genannt werden könnte

Übereinstimmungsmuster für Straßennamen mit Adressen brauchen mehr Zeit für den Aufbau. Aber Sie könnten here besuchen und Ihre RegEx online erstellen.

Hoffe, das hilft.

+0

Vielen Dank für Ihre Hilfe bei der PO Box Muster. Jede Chance, ich kann Sie davon überzeugen, Ihre RegExp Fähigkeiten auf [meine andere Post über das Extrahieren von Autorisierungsnummern] (http://stackoverflow.com/questions/10799500/regex-pattern-to-extract-authorization-numbers) zu verwenden. Ich habe versucht, [GFSkinner's Tool] (http://gskinner.com/RegExr/?) Zu verwenden, das du mit mäßigem Erfolg empfohlen hast, aber ich habe immer noch meine RegExp-Trainingsräder an! Vielen Dank! – regulus

+1

Gern geschehen. Ich habe dem Beitrag eine Lösung hinzugefügt. Hoffe das hilft. – Cylian

2

@Cylian hat eine gute Antwort für den zweiten Teil Ihrer Frage. Ich werde versuchen, das erste zu adressieren. Wenn Ihre einzige Sorge ist, dass Sie ganze Wörter in der Adresse ersetzen dann die folgende Funktion wird tun, was Sie brauchen:

Function AddressReplace(AddressLine As String, _ 
         FullName As String, _ 
         Abbrev As String) 
    AddressReplace = Trim(Replace(" " & AddressLine & " ", _ 
            " " & FullName & " ", _ 
            " " & Abbrev & " ")) 
End Function 

Es umschließt die Adresszeile in einem Öffnungs- und Schließraum, so dass Sie eine Öffnung erfordern kann und schließender Platz für jedes Wort, das Sie ersetzen möchten. Es endet mit einem Trim, um diese temporären Räume loszuwerden.

Das folgende Verfahren prüft den Code und erzeugt die Ausgabe von Ihnen gesuchte:

Sub TestAddressReplace() 
    Debug.Print AddressReplace("123 North 3rd St", "North", "N") 
    Debug.Print AddressReplace("123 Northampton St", "North", "N") 
End Sub 
+1

+1, Schönes Stück Kodierung (ohne RegEx überhaupt.) – Cylian

2

Das USPS verfügt über eine kostenlose Nachschlage-API, um Adressen zu validieren und zu standardisieren. Sie müssen sich für den Dienst registrieren (schnell) und dann Ihre ID/Ihr Passwort in der API verwenden, um auf ihre Website zu springen. Hat die ganze Arbeit für Sie und hat Beispielcode. Kanadische Post hat dasselbe (nicht sicher, dass es frei ist).

https://www.usps.com/business/web-tools-apis/welcome.htm

B. Sevier

Verwandte Themen