วิธีแยกวิเคราะห์ที่อยู่ถนน / ไปรษณีย์แบบอิสระจากข้อความและเป็นส่วนประกอบ


140

เราทำธุรกิจส่วนใหญ่ในสหรัฐอเมริกาและพยายามปรับปรุงประสบการณ์ของผู้ใช้โดยการรวมช่องที่อยู่ทั้งหมดไว้ในพื้นที่ข้อความเดียว แต่มีปัญหาเล็กน้อย:

  • ที่อยู่ที่ผู้ใช้พิมพ์อาจไม่ถูกต้องหรืออยู่ในรูปแบบมาตรฐาน
  • ที่อยู่ต้องแยกออกเป็นส่วน ๆ (ถนนเมืองรัฐ ฯลฯ ) เพื่อดำเนินการชำระเงินด้วยบัตรเครดิต
  • ผู้ใช้อาจป้อนมากกว่าที่อยู่ของตน (เช่นชื่อหรือ บริษัท ด้วย)
  • Google สามารถทำได้ แต่ข้อกำหนดในการให้บริการและขีด จำกัด การสืบค้นเป็นสิ่งที่ห้ามไม่ได้โดยเฉพาะในงบประมาณที่ จำกัด

เห็นได้ชัดว่านี่เป็นคำถามทั่วไป:

มีวิธีแยกที่อยู่ออกจากข้อความรอบ ๆ และแยกเป็นส่วน ๆ หรือไม่? มีนิพจน์ทั่วไปในการแยกวิเคราะห์ที่อยู่หรือไม่


คำตอบด้านล่างมีประโยชน์มากกว่าเนื่องจากไม่เพิกเฉยต่อปัญหาระดับโลกที่อยู่นั้นไม่ตรงกับรูปแบบทั่วไป
Marc Maxmeister

คำตอบ:


295

ฉันเห็นคำถามนี้บ่อยมากเมื่อฉันทำงานให้กับ บริษัท ตรวจสอบที่อยู่ ฉันโพสต์คำตอบที่นี่เพื่อให้โปรแกรมเมอร์ที่ค้นหาคำถามเดียวกันสามารถเข้าถึงได้ง่ายขึ้น บริษัท ที่ฉันดำเนินการตามที่อยู่หลายพันล้านแห่งและเราได้เรียนรู้มากมายในกระบวนการนี้

อันดับแรกเราต้องเข้าใจบางสิ่งเกี่ยวกับที่อยู่

ที่อยู่ไม่ใช่ประจำ

ซึ่งหมายความว่านิพจน์ทั่วไปหมด ฉันได้เห็นมันทั้งหมดตั้งแต่นิพจน์ทั่วไปธรรมดา ๆ ที่จับคู่ที่อยู่ในรูปแบบที่เฉพาะเจาะจงมากจนถึงสิ่งนี้:

/ \ s + (\ d {2,5} \ s +) (?! [a | p] m \ b) (([a-zA-Z | \ s +] {1,5}) {1,2}) ? ([\ s |, |.] +)? (([a-zA-Z | \ s +] {1,30}) {1,4}) (court | ct | street | st | drive | dr | เลน | ln | ถนน | rd | blvd) ([\ s |, |. |;] +)? (([a-zA-Z | \ s +] {1,30}) {1,2}) ([ \ s |, |.] +)? \ b (AK | AL | AR | AZ | CA | CO | CT | DC | DE | FL | GA | GU | HI | IA | ID | IL | IN | KS | KY | LA | MA | MD | ME | MI | MN | MO | MS | MT | NC | ND | NE | NH | NJ | NM | NV | NY | OH | ตกลง | หรือ | PA | RI | SC | SD | TN | TX | UT | VA | VI | VT | WA | WI | WV | WY) ([\ s |, |.] +)? (\ s + \ d {5})? ([\ s |, |.] +) / i

... ด้วยเหตุนี้ไฟล์ระดับบรรทัดกว่า 900+ จะสร้างนิพจน์ทั่วไปที่มีมวลมหาศาลได้ทันทีเพื่อให้เข้ากันได้มากยิ่งขึ้น ฉันไม่แนะนำสิ่งเหล่านี้ (ตัวอย่างเช่นนี่คือซอของ regex ด้านบนซึ่งทำให้เกิดข้อผิดพลาดมากมาย ) ไม่มีสูตรวิเศษง่ายๆที่จะทำให้มันได้ผล ในทางทฤษฎีและตามทฤษฎีไม่สามารถจับคู่ที่อยู่กับนิพจน์ทั่วไปได้

USPS Publication 28จัดทำที่อยู่หลายรูปแบบที่เป็นไปได้พร้อมด้วยคีย์เวิร์ดและตัวแปรทั้งหมด ที่แย่ที่สุดคือที่อยู่มักไม่ชัดเจน คำสามารถมีความหมายมากกว่าหนึ่งสิ่ง ("St" อาจเป็น "Saint" หรือ "Street") และมีคำที่ฉันค่อนข้างมั่นใจว่าพวกเขาประดิษฐ์ขึ้น (ใครจะรู้ว่า "Stravenue" เป็นคำต่อท้ายของถนน)

คุณต้องมีรหัสที่เข้าใจที่อยู่จริงๆและถ้ามีรหัสนั้นก็เป็นความลับทางการค้า แต่คุณอาจจะหมุนตัวเองได้ถ้าคุณทำอย่างนั้นจริงๆ

ที่อยู่มีรูปร่างและขนาดที่ไม่คาดคิด

ต่อไปนี้เป็นที่อยู่ที่สร้างขึ้น (แต่สมบูรณ์):

1)  102 main street
    Anytown, state

2)  400n 600e #2, 52173

3)  p.o. #104 60203

สิ่งเหล่านี้อาจถูกต้อง:

4)  829 LKSDFJlkjsdflkjsdljf Bkpw 12345

5)  205 1105 14 90210

เห็นได้ชัดว่าสิ่งเหล่านี้ไม่ได้มาตรฐาน ไม่รับประกันเครื่องหมายวรรคตอนและการขึ้นบรรทัด นี่คือสิ่งที่เกิดขึ้น:

  1. หมายเลข 1เสร็จสมบูรณ์เนื่องจากมีที่อยู่และเมืองและรัฐ ด้วยข้อมูลดังกล่าวมีการระบุที่อยู่เพียงพอและถือได้ว่า "ส่งมอบได้" (โดยมีการกำหนดมาตรฐาน)

  2. หมายเลข 2เสร็จสมบูรณ์เนื่องจากประกอบด้วยที่อยู่ (พร้อมหมายเลขรอง / หน่วย) และรหัสไปรษณีย์ 5 หลักซึ่งเพียงพอสำหรับระบุที่อยู่

  3. หมายเลข 3เป็นรูปแบบตู้ไปรษณีย์ที่สมบูรณ์เนื่องจากมีรหัสไปรษณีย์

  4. หมายเลข 4ก็สมบูรณ์เช่นกันเนื่องจากรหัสไปรษณีย์ไม่ซ้ำกันหมายความว่านิติบุคคลหรือ บริษัท เอกชนได้ซื้อพื้นที่ที่อยู่นั้น รหัสไปรษณีย์เฉพาะใช้สำหรับพื้นที่จัดส่งที่มีปริมาณมากหรือกระจุกตัว ทุกสิ่งที่ระบุถึงรหัสไปรษณีย์ 12345 จะส่งไปที่ General Electric ใน Schenectady, NY ตัวอย่างนี้ไม่สามารถเข้าถึงใครได้โดยเฉพาะ แต่ USPS จะยังคงส่งมอบได้

  5. เลข 5ครบด้วยเชื่อหรือไม่ ด้วยตัวเลขเหล่านั้นคุณสามารถค้นพบที่อยู่แบบเต็มเมื่อแยกวิเคราะห์กับฐานข้อมูลของที่อยู่ที่เป็นไปได้ทั้งหมด การกรอกทิศทางที่ขาดหายไปตัวกำหนดรองและรหัส ZIP + 4 เป็นเรื่องเล็กน้อยเมื่อคุณเห็นตัวเลขแต่ละตัวเป็นส่วนประกอบ นี่คือสิ่งที่ดูเหมือนขยายอย่างเต็มที่และได้มาตรฐาน:

205 N 1105 W Apt 14

เบเวอร์ลีฮิลส์แคลิฟอร์เนีย 90210-5221

ข้อมูลที่อยู่ไม่ใช่ของคุณเอง

ในประเทศส่วนใหญ่ที่ให้ข้อมูลที่อยู่อย่างเป็นทางการแก่ผู้ขายที่ได้รับใบอนุญาตข้อมูลที่อยู่นั้นเป็นของหน่วยงานที่กำกับดูแล ในสหรัฐอเมริกา USPS เป็นเจ้าของที่อยู่ เช่นเดียวกับ Canada Post, Royal Mail และอื่น ๆ แม้ว่าแต่ละประเทศจะบังคับใช้หรือกำหนดความเป็นเจ้าของแตกต่างกันเล็กน้อย การรู้สิ่งนี้เป็นสิ่งสำคัญเนื่องจากโดยปกติจะห้ามทำวิศวกรรมย้อนกลับฐานข้อมูลที่อยู่ คุณต้องระมัดระวังในการรับจัดเก็บและใช้ข้อมูล

Google Maps เป็นสิ่งที่ใช้กันทั่วไปสำหรับการแก้ไขที่อยู่อย่างรวดเร็ว แต่TOSค่อนข้างห้ามปราม ตัวอย่างเช่นคุณไม่สามารถใช้ข้อมูลหรือ API โดยไม่แสดง Google Map และเพื่อวัตถุประสงค์ที่ไม่ใช่เชิงพาณิชย์เท่านั้น (เว้นแต่คุณจะจ่ายเงิน) และคุณไม่สามารถจัดเก็บข้อมูลได้ (ยกเว้นการแคชชั่วคราว) มีเหตุผล. ข้อมูลของ Google เป็นข้อมูลที่ดีที่สุดในโลก อย่างไรก็ตาม Google Maps ไม่ได้ยืนยันที่อยู่ ถ้าอยู่ไม่อยู่ก็จะยังคงแสดงให้คุณที่อยู่จะเป็นอย่างไรถ้ามันไม่ได้มีอยู่ (ลองบนถนนของคุณเองใช้บ้านเลขที่คุณรู้ว่าไม่อยู่) สิ่งนี้มีประโยชน์ในบางครั้ง แต่โปรดทราบว่า

นโยบายการใช้งานของ Nominatim มีข้อ จำกัด ในทำนองเดียวกันโดยเฉพาะอย่างยิ่งสำหรับการใช้งานในปริมาณมากและเชิงพาณิชย์และข้อมูลส่วนใหญ่มาจากแหล่งที่มาที่ไม่เสียค่าใช้จ่ายดังนั้นจึงไม่ได้รับการดูแลอย่างดี (เช่นลักษณะของโครงการที่เปิดอยู่) - อย่างไรก็ตามสิ่งนี้ยังคงเหมาะกับ ความต้องการของคุณ ได้รับการสนับสนุนจากชุมชนที่ยอดเยี่ยม

USPS เองก็มี API แต่มันลดลงไปมากและไม่มีการรับประกันหรือการสนับสนุน นอกจากนี้ยังอาจใช้งานยาก บางคนใช้เท่าที่จำเป็นโดยไม่มีปัญหา แต่พลาดง่ายมากที่ USPS ต้องการให้คุณใช้ API เพื่อยืนยันที่อยู่เพื่อจัดส่งผ่านเท่านั้น

ผู้คนคาดหวังว่าที่อยู่จะยาก

น่าเสียดายที่เราได้กำหนดเงื่อนไขให้สังคมของเราคาดว่าที่อยู่จะซับซ้อน มีบทความเกี่ยวกับ UX ที่ดีมากมายบนอินเทอร์เน็ตเกี่ยวกับเรื่องนี้ แต่ความจริงก็คือหากคุณมีแบบฟอร์มที่อยู่ที่มีแต่ละช่องนั่นคือสิ่งที่ผู้ใช้คาดหวังแม้ว่าจะทำให้ที่อยู่ edge-case ยากขึ้นที่ไม่ตรงกับ จัดรูปแบบฟอร์มที่คาดหวังหรือบางทีแบบฟอร์มต้องใช้ฟิลด์ที่ไม่ควร หรือผู้ใช้ไม่รู้ว่าจะใส่ส่วนใดส่วนหนึ่งของที่อยู่ของตน

วันนี้ฉันสามารถดำเนินการต่อเกี่ยวกับ UX ที่ไม่ดีของแบบฟอร์มการชำระเงินได้ แต่ฉันจะบอกว่าการรวมที่อยู่ลงในช่องเดียวจะเป็นการเปลี่ยนแปลงที่น่ายินดี - ผู้คนจะสามารถพิมพ์ที่อยู่ของตนได้ตามที่เห็นสมควร แทนที่จะพยายามหารูปแบบที่ยาวของคุณ อย่างไรก็ตามการเปลี่ยนแปลงนี้จะเป็นสิ่งที่ไม่คาดคิดและผู้ใช้อาจพบว่าการเปลี่ยนแปลงนี้สั่นสะเทือนเล็กน้อยในตอนแรก เพียงแค่ตระหนักถึงสิ่งนั้น

ส่วนหนึ่งของความเจ็บปวดนี้สามารถบรรเทาได้ด้วยการวางสนามประเทศไว้ด้านหน้าก่อนที่อยู่ เมื่อกรอกข้อมูลในฟิลด์ประเทศก่อนคุณจะทราบวิธีทำให้แบบฟอร์มของคุณปรากฏ บางทีคุณอาจมีวิธีที่ดีในการจัดการกับที่อยู่ในเขตข้อมูลเดียวในสหรัฐอเมริกาดังนั้นหากพวกเขาเลือกสหรัฐอเมริกาคุณสามารถลดแบบฟอร์มของคุณเป็นช่องเดียวหรือแสดงช่ององค์ประกอบ สิ่งที่ต้องคิด!

ตอนนี้เรารู้แล้วว่าทำไมมันยาก คุณทำอะไรได้บ้าง

USPS ให้ใบอนุญาตผู้ขายผ่านกระบวนการที่เรียกว่า CASS ™ Certification เพื่อให้ที่อยู่ที่ได้รับการยืนยันแก่ลูกค้า ผู้ขายเหล่านี้สามารถเข้าถึงฐานข้อมูล USPS ซึ่งอัพเดททุกเดือน ซอฟต์แวร์ของพวกเขาต้องเป็นไปตามมาตรฐานที่เข้มงวดจึงจะได้รับการรับรองและมักไม่จำเป็นต้องมีข้อตกลงเกี่ยวกับข้อกำหนดที่ จำกัด ดังที่กล่าวไว้ข้างต้น

มี บริษัท ที่ได้รับการรับรอง CASS จำนวนมากที่สามารถประมวลผลรายการหรือมี API ได้: Melissa Data, Experian QAS และ SmartyStreets เพื่อตั้งชื่อไม่กี่แห่ง

(เนื่องจากได้รับความเสียหายจากการ "โฆษณา" ฉันจึงได้ตัดคำตอบของตัวเอง ณ จุดนี้คุณต้องหาวิธีแก้ปัญหาที่เหมาะกับคุณ)

ความจริง:จริงๆแล้วฉันไม่ได้ทำงานใน บริษัท เหล่านี้ มันไม่ใช่โฆษณา


1
ที่อยู่อเมริกาใต้ (อุรุกวัย) ล่ะ : D
Bart Calixto

11
@ ไบรอัน - บางทีอาจเป็นเพราะผู้ใช้ให้ข้อมูลที่เป็นประโยชน์มากมายสำหรับผู้ที่อ่านคำถามและคำตอบไม่ว่าพวกเขาจะเลือกใช้ผลิตภัณฑ์ของ บริษัท ของเขาหรือไม่ก็ตาม
Zarepheth

7
@ ไบรอันไซต์เหล่านั้นเป็นเครื่องขูดเนื้อหา พวกเขากำลังรวบรวมเนื้อหาเพื่อรับการจัดอันดับ SERP ฉันไม่เคยเห็นมาก่อน ฉันไม่เคยโพสต์เนื้อหานี้ก่อนหรือหลังที่อื่น
Matt

2
@khuderm ฉันสังเกตเห็นตอนที่ฉันอ่านความคิดเห็นของคุณว่าความคิดเห็นที่ไม่เห็นด้วยทั้งหมดหายไป ไม่แน่ใจว่าเกิดขึ้นได้อย่างไร / เมื่อใด แต่อย่างไรก็ตามโปรดดูประวัติการแก้ไขคำตอบของฉันแล้วคุณจะพบข้อมูลอ้างอิงโดยตรงไปยังโปรแกรมแยกที่อยู่ในสหรัฐอเมริกาซึ่งอาจช่วยคุณได้ ฉันสร้างมันขึ้นเมื่อฉันทำงานที่สุดท้าย แต่เป็นรหัสที่เป็นกรรมสิทธิ์ดังนั้นฉันจึงไม่สามารถแบ่งปันได้ ... แต่มันมีอยู่จริง หวังว่าจะเป็นประโยชน์
Matt

2
อ๊ะ. ขออภัย @Matt. ฉันเริ่มติดตามคุณผ่านคำถามของคุณและ Github น่าประทับใจทีเดียว
Sayka

29

libpostal: ไลบรารีโอเพ่นซอร์สเพื่อแยกวิเคราะห์ที่อยู่การฝึกอบรมกับข้อมูลจาก OpenStreetMap, OpenAddresses และ OpenCage

https://github.com/openvenues/libpostal ( ข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ )

เครื่องมือ / บริการอื่น ๆ :


14

มีตัวแยกวิเคราะห์ที่อยู่หลายถนน พวกเขามาในสองรสชาติพื้นฐาน - ที่มีฐานข้อมูลชื่อสถานที่และชื่อถนนและที่ไม่มี

โปรแกรมแยกวิเคราะห์ที่อยู่ของนิพจน์ทั่วไปสามารถรับอัตราความสำเร็จได้ถึง 95% โดยไม่มีปัญหามากนัก จากนั้นคุณเริ่มกดปุ่มกรณีที่ผิดปกติ Perl หนึ่งใน CPAN "Geo :: StreetAddress :: US" เป็นสิ่งที่ดี มีพอร์ต Python และ Javascript ซึ่งเป็นโอเพ่นซอร์สทั้งหมด ฉันมีเวอร์ชันที่ปรับปรุงแล้วใน Python ซึ่งทำให้อัตราความสำเร็จเพิ่มขึ้นเล็กน้อยโดยจัดการกับกรณีต่างๆได้มากขึ้น เพื่อให้ได้สิทธิ์ 3% ล่าสุดคุณต้องมีฐานข้อมูลเพื่อช่วยในการลดความสับสน

ฐานข้อมูลที่มีรหัสไปรษณีย์ 3 หลักชื่อและตัวย่อของรัฐในสหรัฐอเมริกาเป็นตัวช่วยที่ดี เมื่อโปรแกรมแยกวิเคราะห์เห็นรหัสไปรษณีย์และชื่อรัฐที่สอดคล้องกันก็จะเริ่มล็อกรูปแบบได้ ซึ่งได้ผลดีมากสำหรับสหรัฐอเมริกาและสหราชอาณาจักร

การแยกวิเคราะห์ที่อยู่ที่ถูกต้องจะเริ่มจากส่วนท้ายและย้อนกลับ นั่นเป็นวิธีที่ระบบ USPS ทำ ที่อยู่มีความคลุมเครืออย่างน้อยที่สุดในตอนท้ายซึ่งชื่อประเทศชื่อเมืองและรหัสไปรษณีย์ค่อนข้างง่ายต่อการจดจำ โดยปกติชื่อถนนสามารถแยกได้ สถานที่บนท้องถนนเป็นสถานที่ที่ซับซ้อนที่สุดในการแยกวิเคราะห์ คุณจะพบกับสิ่งต่างๆเช่น "ชั้นห้า" และ "Staples Pavillion" นั่นคือเวลาที่ฐานข้อมูลเป็นตัวช่วยที่ยิ่งใหญ่


นอกจากนี้ยังมีโมดูล CPAN Lingua: EN :: AddressParse แม้ว่าจะช้ากว่า "Geo :: StreetAddress :: US แต่ก็ให้อัตราความสำเร็จที่สูงกว่า
Kim Ryan

8

UPDATE: ขณะนี้ Geocode.xyz ใช้งานได้ทั่วโลก สำหรับตัวอย่างดู https://geocode.xyz

สำหรับสหรัฐอเมริกาเม็กซิโกและแคนาดาโปรดดู geocoder.ca

ตัวอย่างเช่น:

อินพุต: บางอย่างเกิดขึ้นใกล้สี่แยกหลักและอาร์เทอร์ kill rd new york

เอาท์พุต:

<geodata>
  <latt>40.5123510000</latt>
  <longt>-74.2500500000</longt>
  <AreaCode>347,718</AreaCode>
  <TimeZone>America/New_York</TimeZone>
  <standard>
    <street1>main</street1>
    <street2>arthur kill</street2>
    <stnumber/>
    <staddress/>
    <city>STATEN ISLAND</city>
    <prov>NY</prov>
    <postal>11385</postal>
    <confidence>0.9</confidence>
  </standard>
</geodata>

คุณสามารถตรวจสอบผลลัพธ์ในเว็บอินเตอร์เฟสหรือรับเอาต์พุตเป็น Json หรือ Jsonp เช่น. ฉันกำลังมองหาร้านอาหารแถว 123 Main Street, New York


คุณติดตั้งระบบแยกวิเคราะห์ที่อยู่โดยใช้ openaddress อย่างไร? คุณใช้กลยุทธ์กำลังดุร้ายหรือไม่?
Nithin K Anil

1
คำว่า 'กำลังดุร้าย' หมายความว่าอย่างไร? การแบ่งข้อความออกเป็นชุดค่าผสมที่เป็นไปได้ทั้งหมดของสตริงที่อยู่ที่เป็นไปได้และการเปรียบเทียบแต่ละรายการกับฐานข้อมูลของที่อยู่นั้นไม่สามารถใช้ได้จริงและจะใช้เวลาในการให้คำตอบมากกว่าระบบนี้ Openaddresses เป็นหนึ่งในแหล่งข้อมูลสำหรับการสร้าง 'ชุดฝึก' ของรูปแบบที่อยู่สำหรับอัลกอริทึม ใช้ข้อมูลนี้เพื่อแยกวิเคราะห์ที่อยู่ออกจากข้อความที่ไม่มีโครงสร้าง
Ervin Ruci

2
อีกระบบที่คล้ายกันคือ Geo :: libpostal ( perltricks.com/article/announcing-geo--libpostal ) พวกเขายังใช้ openstreetmap และ openaddresses เพื่อสร้างเทมเพลตที่อยู่ได้ทันที
Ervin Ruci

ฉันเพิ่งทดสอบ geoparser ของ geocode.xyz (ส่งข้อความรับตำแหน่งกลับ) กับที่อยู่จริงหลายร้อยรายการ ป.ร. ให้ไว้เคียงข้างกับ API แผนที่ของ Google และชุดทั่วโลกของที่อยู่geocode.xyz's scantextวิธีการล้มเหลวมากที่สุดของเวลา โดยมักจะเลือก "เจนีวาสหรัฐอเมริกา" มากกว่า "เจนีวาสวิตเซอร์แลนด์" และโดยทั่วไปสหรัฐฯมีอคติ
Marc Maxmeister

มันขึ้นอยู่กับบริบท geocode.xyz/?scantext=Geneva,%20สวิตเซอร์แลนด์จะผลิต: Match Location Geneva, Switzerland, CH Confidence Score: 0.8 ในขณะที่geocode.xyz/?scantext=Geneva,%20USAจะสร้าง Match Location Geneva, US Confidence Score: 1.0 ด้วย คุณสามารถแบ่ง bias ได้ดังนี้geocode.xyz/?scantext=Geneva,%20USA®ion=CH
Ervin Ruci

4

ไม่มีรหัส? สำหรับความอัปยศ!

นี่คือตัวแยกวิเคราะห์ที่อยู่ JavaScript แบบง่าย มันค่อนข้างแย่สำหรับทุกเหตุผลที่ Matt ให้ไว้ในวิทยานิพนธ์ของเขาข้างต้น (ซึ่งฉันเห็นด้วยเกือบ 100%: ที่อยู่เป็นประเภทที่ซับซ้อนและมนุษย์ทำผิดพลาดดีกว่าที่จะจ้างบุคคลภายนอกและทำสิ่งนี้โดยอัตโนมัติ - เมื่อคุณสามารถทำได้)

แต่แทนที่จะร้องไห้ฉันตัดสินใจลอง:

รหัสนี้ใช้ได้สำหรับการแยกวิเคราะห์ผลลัพธ์ Esri ส่วนใหญ่สำหรับfindAddressCandidateและยังมี geocoders อื่น ๆ (ย้อนกลับ) ที่แสดงที่อยู่บรรทัดเดียวโดยที่ถนน / เมือง / รัฐถูกคั่นด้วยเครื่องหมายจุลภาค คุณสามารถขยายได้หากต้องการหรือเขียนตัวแยกวิเคราะห์เฉพาะประเทศ หรือใช้เป็นกรณีศึกษาว่าแบบฝึกหัดนี้ท้าทายแค่ไหนหรือใช้ JavaScript ได้แค่ไหน ฉันยอมรับว่าฉันใช้เวลาประมาณสามสิบนาทีในการทำสิ่งนี้ (การทำซ้ำในอนาคตอาจเพิ่มแคชการตรวจสอบความถูกต้องของซิปและการค้นหาสถานะตลอดจนบริบทตำแหน่งของผู้ใช้) แต่ใช้ได้กับกรณีการใช้งานของฉัน: ผู้ใช้ปลายทางเห็นแบบฟอร์มที่แยกวิเคราะห์การตอบสนองการค้นหารหัสภูมิศาสตร์เป็น 4 กล่องข้อความ หากการแยกวิเคราะห์ที่อยู่ผิดพลาด (ซึ่งหาได้ยากเว้นแต่ว่าแหล่งข้อมูลไม่ดี) ก็ไม่ใช่เรื่องใหญ่ - ผู้ใช้จะต้องตรวจสอบและแก้ไข! (แต่สำหรับโซลูชันอัตโนมัติอาจละทิ้ง / เพิกเฉยหรือตั้งค่าสถานะเป็นข้อผิดพลาดเพื่อให้ dev รองรับรูปแบบใหม่หรือแก้ไขข้อมูลต้นทาง)

/* 
address assumptions:
- US addresses only (probably want separate parser for different countries)
- No country code expected.
- if last token is a number it is probably a postal code
-- 5 digit number means more likely
- if last token is a hyphenated string it might be a postal code
-- if both sides are numeric, and in form #####-#### it is more likely
- if city is supplied, state will also be supplied (city names not unique)
- zip/postal code may be omitted even if has city & state
- state may be two-char code or may be full state name.
- commas: 
-- last comma is usually city/state separator
-- second-to-last comma is possibly street/city separator
-- other commas are building-specific stuff that I don't care about right now.
- token count:
-- because units, street names, and city names may contain spaces token count highly variable.
-- simplest address has at least two tokens: 714 OAK
-- common simple address has at least four tokens: 714 S OAK ST
-- common full (mailing) address has at least 5-7:
--- 714 OAK, RUMTOWN, VA 59201
--- 714 S OAK ST, RUMTOWN, VA 59201
-- complex address may have a dozen or more:
--- MAGICICIAN SUPPLY, LLC, UNIT 213A, MAGIC TOWN MALL, 13 MAGIC CIRCLE DRIVE, LAND OF MAGIC, MA 73122-3412
*/

var rawtext = $("textarea").val();
var rawlist = rawtext.split("\n");

function ParseAddressEsri(singleLineaddressString) {
  var address = {
    street: "",
    city: "",
    state: "",
    postalCode: ""
  };

  // tokenize by space (retain commas in tokens)
  var tokens = singleLineaddressString.split(/[\s]+/);
  var tokenCount = tokens.length;
  var lastToken = tokens.pop();
  if (
    // if numeric assume postal code (ignore length, for now)
    !isNaN(lastToken) ||
    // if hyphenated assume long zip code, ignore whether numeric, for now
    lastToken.split("-").length - 1 === 1) {
    address.postalCode = lastToken;
    lastToken = tokens.pop();
  }

  if (lastToken && isNaN(lastToken)) {
    if (address.postalCode.length && lastToken.length === 2) {
      // assume state/province code ONLY if had postal code
      // otherwise it could be a simple address like "714 S OAK ST"
      // where "ST" for "street" looks like two-letter state code
      // possibly this could be resolved with registry of known state codes, but meh. (and may collide anyway)
      address.state = lastToken;
      lastToken = tokens.pop();
    }
    if (address.state.length === 0) {
      // check for special case: might have State name instead of State Code.
      var stateNameParts = [lastToken.endsWith(",") ? lastToken.substring(0, lastToken.length - 1) : lastToken];

      // check remaining tokens from right-to-left for the first comma
      while (2 + 2 != 5) {
        lastToken = tokens.pop();
        if (!lastToken) break;
        else if (lastToken.endsWith(",")) {
          // found separator, ignore stuff on left side
          tokens.push(lastToken); // put it back
          break;
        } else {
          stateNameParts.unshift(lastToken);
        }
      }
      address.state = stateNameParts.join(' ');
      lastToken = tokens.pop();
    }
  }

  if (lastToken) {
    // here is where it gets trickier:
    if (address.state.length) {
      // if there is a state, then assume there is also a city and street.
      // PROBLEM: city may be multiple words (spaces)
      // but we can pretty safely assume next-from-last token is at least PART of the city name
      // most cities are single-name. It would be very helpful if we knew more context, like
      // the name of the city user is in. But ignore that for now.
      // ideally would have zip code service or lookup to give city name for the zip code.
      var cityNameParts = [lastToken.endsWith(",") ? lastToken.substring(0, lastToken.length - 1) : lastToken];

      // assumption / RULE: street and city must have comma delimiter
      // addresses that do not follow this rule will be wrong only if city has space
      // but don't care because Esri formats put comma before City
      var streetNameParts = [];

      // check remaining tokens from right-to-left for the first comma
      while (2 + 2 != 5) {
        lastToken = tokens.pop();
        if (!lastToken) break;
        else if (lastToken.endsWith(",")) {
          // found end of street address (may include building, etc. - don't care right now)
          // add token back to end, but remove trailing comma (it did its job)
          tokens.push(lastToken.endsWith(",") ? lastToken.substring(0, lastToken.length - 1) : lastToken);
          streetNameParts = tokens;
          break;
        } else {
          cityNameParts.unshift(lastToken);
        }
      }
      address.city = cityNameParts.join(' ');
      address.street = streetNameParts.join(' ');
    } else {
      // if there is NO state, then assume there is NO city also, just street! (easy)
      // reasoning: city names are not very original (Portland, OR and Portland, ME) so if user wants city they need to store state also (but if you are only ever in Portlan, OR, you don't care about city/state)
      // put last token back in list, then rejoin on space
      tokens.push(lastToken);
      address.street = tokens.join(' ');
    }
  }
  // when parsing right-to-left hard to know if street only vs street + city/state
  // hack fix for now is to shift stuff around.
  // assumption/requirement: will always have at least street part; you will never just get "city, state"  
  // could possibly tweak this with options or more intelligent parsing&sniffing
  if (!address.city && address.state) {
    address.city = address.state;
    address.state = '';
  }
  if (!address.street) {
    address.street = address.city;
    address.city = '';
  }

  return address;
}

// get list of objects with discrete address properties
var addresses = rawlist
  .filter(function(o) {
    return o.length > 0
  })
  .map(ParseAddressEsri);
$("#output").text(JSON.stringify(addresses));
console.log(addresses);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea>
27488 Stanford Ave, Bowden, North Dakota
380 New York St, Redlands, CA 92373
13212 E SPRAGUE AVE, FAIR VALLEY, MD 99201
1005 N Gravenstein Highway, Sebastopol CA 95472
A. P. Croll &amp; Son 2299 Lewes-Georgetown Hwy, Georgetown, DE 19947
11522 Shawnee Road, Greenwood, DE 19950
144 Kings Highway, S.W. Dover, DE 19901
Intergrated Const. Services 2 Penns Way Suite 405, New Castle, DE 19720
Humes Realty 33 Bridle Ridge Court, Lewes, DE 19958
Nichols Excavation 2742 Pulaski Hwy, Newark, DE 19711
2284 Bryn Zion Road, Smyrna, DE 19904
VEI Dover Crossroads, LLC 1500 Serpentine Road, Suite 100 Baltimore MD 21
580 North Dupont Highway, Dover, DE 19901
P.O. Box 778, Dover, DE 19903
714 S OAK ST
714 S OAK ST, RUM TOWN, VA, 99201
3142 E SPRAGUE AVE, WHISKEY VALLEY, WA 99281
27488 Stanford Ave, Bowden, North Dakota
380 New York St, Redlands, CA 92373
</textarea>
<div id="output">
</div>


ข้อจำกัดความรับผิดชอบ: ลูกค้าของฉันเป็นเจ้าของข้อมูลที่อยู่และเรียกใช้เซิร์ฟเวอร์ Esri ของตนเอง หากคุณคว้าข้อมูลจาก Google, OSM, ArcGisOnline หรือที่ใดก็ตามให้แน่ใจว่ามันมีการตกลงในการจัดเก็บและใช้งานได้ (บริการจำนวนมากมีข้อ จำกัด ในวิธีการที่คุณสามารถจัดเก็บและนานเท่าไหร่)
nothingisnecessary

คำตอบแรกข้างต้นเป็นกรณีที่น่าสนใจว่าปัญหานี้ไม่สามารถแก้ไขได้ด้วย regexes หากคุณกำลังจัดการกับรายการที่อยู่ส่วนกลาง 200 ประเทศมีข้อยกเว้นมากเกินไป ในการทดสอบของฉันคุณสามารถกำหนดประเทศจากสตริงได้ค่อนข้างน่าเชื่อถือจากนั้นค้นหา regex specifc สำหรับแต่ละประเทศซึ่งอาจเป็นวิธีการทำงานของ API ที่ดีกว่า
Marc Maxmeister

2

หากคุณต้องการพึ่งพา OSM data libpostalมีประสิทธิภาพมากและจัดการคำเตือนที่พบบ่อยที่สุดจำนวนมากด้วยอินพุตที่อยู่


ฉันคิดว่าคำตอบของคุณซ้ำกับโพสต์นี้ ข้อเสนอแนะที่ดีแม้ว่า
Michael

2

อีกทางเลือกหนึ่งสำหรับที่อยู่ในสหรัฐอเมริกาคือYAddress (สร้างโดย บริษัท ที่ฉันทำงานให้)

หลายคำตอบสำหรับคำถามนี้แนะนำให้ใช้เครื่องมือ geocoding เป็นวิธีแก้ปัญหา สิ่งสำคัญคือต้องไม่สับสนระหว่างการแยกวิเคราะห์ที่อยู่และการระบุพิกัดทางภูมิศาสตร์ พวกเขาไม่เหมือนกัน แม้ว่า geocoders อาจแบ่งแอดเดรสออกเป็นส่วนประกอบเพื่อประโยชน์ข้างเคียง แต่ก็มักจะอาศัยชุดที่อยู่ที่ไม่ได้มาตรฐาน ซึ่งหมายความว่าที่อยู่ที่แยกวิเคราะห์ทางภูมิศาสตร์อาจไม่เหมือนกับที่อยู่อย่างเป็นทางการ ตัวอย่างเช่นสิ่งที่ Google geocoding API เรียกว่า "6th Ave" ในแมนฮัตตัน USPS เรียก "Avenue of the Americas"


2

สำหรับการแยกวิเคราะห์ที่อยู่ในสหรัฐอเมริกา

ฉันชอบใช้แพ็คเกจ usaddress ที่มีอยู่ใน pip สำหรับ usaddress เท่านั้น

python3 -m pip install usaddress

เอกสาร
PyPi

สิ่งนี้ใช้ได้ดีสำหรับฉันสำหรับที่อยู่ในสหรัฐอเมริกา

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# address_parser.py
import sys
from usaddress import tag
from json import dumps, loads

if __name__ == '__main__':
    tag_mapping = {
        'Recipient': 'recipient',
        'AddressNumber': 'addressStreet',
        'AddressNumberPrefix': 'addressStreet',
        'AddressNumberSuffix': 'addressStreet',
        'StreetName': 'addressStreet',
        'StreetNamePreDirectional': 'addressStreet',
        'StreetNamePreModifier': 'addressStreet',
        'StreetNamePreType': 'addressStreet',
        'StreetNamePostDirectional': 'addressStreet',
        'StreetNamePostModifier': 'addressStreet',
        'StreetNamePostType': 'addressStreet',
        'CornerOf': 'addressStreet',
        'IntersectionSeparator': 'addressStreet',
        'LandmarkName': 'addressStreet',
        'USPSBoxGroupID': 'addressStreet',
        'USPSBoxGroupType': 'addressStreet',
        'USPSBoxID': 'addressStreet',
        'USPSBoxType': 'addressStreet',
        'BuildingName': 'addressStreet',
        'OccupancyType': 'addressStreet',
        'OccupancyIdentifier': 'addressStreet',
        'SubaddressIdentifier': 'addressStreet',
        'SubaddressType': 'addressStreet',
        'PlaceName': 'addressCity',
        'StateName': 'addressState',
        'ZipCode': 'addressPostalCode',
    }
    try:
        address, _ = tag(' '.join(sys.argv[1:]), tag_mapping=tag_mapping)
    except:
        with open('failed_address.txt', 'a') as fp:
            fp.write(sys.argv[1] + '\n')
        print(dumps({}))
    else:
        print(dumps(dict(address)))

เรียกใช้ address_parser.py

 python3 address_parser.py 9757 East Arcadia Ave. Saugus MA 01906
 {"addressStreet": "9757 East Arcadia Ave.", "addressCity": "Saugus", "addressState": "MA", "addressPostalCode": "01906"}

0

ฉันไปงานปาร์ตี้สายนี่คือสคริปต์ Excel VBA ที่ฉันเขียนเมื่อหลายปีก่อนสำหรับออสเตรเลีย สามารถแก้ไขได้อย่างง่ายดายเพื่อรองรับประเทศอื่น ๆ ฉันได้สร้างที่เก็บ GitHub ของรหัส C # ที่นี่ ฉันโฮสต์ไว้ในไซต์ของฉันและคุณสามารถดาวน์โหลดได้ที่นี่: http://jeremythompson.net/rocks/ParseAddress.xlsm

กลยุทธ์

สำหรับประเทศใด ๆ ที่มี PostCode ที่เป็นตัวเลขหรือสามารถจับคู่กับ RegEx กลยุทธ์ของฉันใช้ได้ดีมาก:

  1. อันดับแรกเราจะตรวจพบชื่อและนามสกุลซึ่งถือว่าเป็นบรรทัดบนสุด ง่ายต่อการข้ามชื่อและเริ่มต้นด้วยที่อยู่โดยการยกเลิกการเลือกช่องทำเครื่องหมาย (เรียกว่า 'ชื่อคือแถวบนสุด' ดังที่แสดงด้านล่าง)

  2. ถัดไปปลอดภัยที่จะคาดหวังว่าที่อยู่ซึ่งประกอบด้วยถนนและหมายเลขจะมาก่อนชานเมืองและ St, Pde, Ave, Av, Rd, Cres, loop และอื่น ๆ เป็นตัวคั่น

  3. การตรวจจับชานเมืองเทียบกับรัฐและแม้แต่ประเทศก็สามารถหลอกลวงผู้แยกวิเคราะห์ที่ซับซ้อนที่สุดได้เนื่องจากอาจมีข้อขัดแย้งได้ เพื่อเอาชนะสิ่งนี้ฉันใช้การค้นหา PostCode ตามข้อเท็จจริงที่ว่าหลังจากลอกหมายเลข Street และ Apartment / Unit ตลอดจน PoBox, Ph, Fax , Mobile ฯลฯ จะมีเพียงหมายเลข PostCode เท่านั้น นี่เป็นเรื่องง่ายที่จะจับคู่กับ regEx เพื่อค้นหาชานเมืองและประเทศ

บริการไปรษณีย์แห่งชาติของคุณจะให้รายการรหัสไปรษณีย์พร้อมเขตชานเมืองและรัฐโดยไม่เสียค่าใช้จ่ายซึ่งคุณสามารถจัดเก็บไว้ในแผ่นงาน excel ตาราง db ไฟล์ text / json / xml เป็นต้น

  1. ในที่สุดเนื่องจากรหัสไปรษณีย์บางรหัสมีหลายชานเมืองเราจึงตรวจสอบว่าชานเมืองใดปรากฏในที่อยู่

ตัวอย่าง

ป้อนคำอธิบายภาพที่นี่

รหัส VBA

การปฏิเสธความรับผิดฉันรู้ว่ารหัสนี้ไม่สมบูรณ์แบบหรือเขียนได้ดี แต่มันง่ายมากที่จะแปลงเป็นภาษาโปรแกรมใด ๆ และเรียกใช้ในแอปพลิเคชันประเภทใดก็ได้กลยุทธ์คือคำตอบขึ้นอยู่กับประเทศและกฎของคุณใช้รหัสนี้เป็นตัวอย่าง :

Option Explicit

Private Const TopRow As Integer = 0

Public Sub ParseAddress()
Dim strArr() As String
Dim sigRow() As String
Dim i As Integer
Dim j As Integer
Dim k As Integer
Dim Stat As String
Dim SpaceInName As Integer
Dim Temp As String
Dim PhExt As String

On Error Resume Next

Temp = ActiveSheet.Range("Address")

'Split info into array
strArr = Split(Temp, vbLf)

'Trim the array
For i = 0 To UBound(strArr)
strArr(i) = VBA.Trim(strArr(i))
Next i

'Remove empty items/rows    
ReDim sigRow(LBound(strArr) To UBound(strArr))
For i = LBound(strArr) To UBound(strArr)
    If Trim(strArr(i)) <> "" Then
        sigRow(j) = strArr(i)
        j = j + 1
    End If
Next i
ReDim Preserve sigRow(LBound(strArr) To j)

'Find the name (MUST BE ON THE FIRST ROW UNLESS CHECKBOX UNTICKED)
i = TopRow
If ActiveSheet.Shapes("chkFirst").ControlFormat.Value = 1 Then

SpaceInName = InStr(1, sigRow(i), " ", vbTextCompare) - 1

If ActiveSheet.Shapes("chkConfirm").ControlFormat.Value = 0 Then
ActiveSheet.Range("FirstName") = VBA.Left(sigRow(i), SpaceInName)
Else
 If MsgBox("First Name: " & VBA.Mid$(sigRow(i), 1, SpaceInName), vbQuestion + vbYesNo, "Confirm Details") = vbYes Then ActiveSheet.Range("FirstName") = VBA.Left(sigRow(i), SpaceInName)
End If

If ActiveSheet.Shapes("chkConfirm").ControlFormat.Value = 0 Then
ActiveSheet.Range("Surname") = VBA.Mid(sigRow(i), SpaceInName + 2)
Else
  If MsgBox("Surame: " & VBA.Mid(sigRow(i), SpaceInName + 2), vbQuestion + vbYesNo, "Confirm Details") = vbYes Then ActiveSheet.Range("Surname") = VBA.Mid(sigRow(i), SpaceInName + 2)
End If
sigRow(i) = ""
End If

'Find the Street by looking for a "St, Pde, Ave, Av, Rd, Cres, loop, etc"
For i = 1 To UBound(sigRow)
If Len(sigRow(i)) > 0 Then
    For j = 0 To 8
    If InStr(1, VBA.UCase(sigRow(i)), Street(j), vbTextCompare) > 0 Then

    'Find the position of the street in order to get the suburb
    SpaceInName = InStr(1, VBA.UCase(sigRow(i)), Street(j), vbTextCompare) + Len(Street(j)) - 1

    'If its a po box then add 5 chars
    If VBA.Right(Street(j), 3) = "BOX" Then SpaceInName = SpaceInName + 5

    If ActiveSheet.Shapes("chkConfirm").ControlFormat.Value = 0 Then
    ActiveSheet.Range("Street") = VBA.Mid(sigRow(i), 1, SpaceInName)
    Else
      If MsgBox("Street Address: " & VBA.Mid(sigRow(i), 1, SpaceInName), vbQuestion + vbYesNo, "Confirm Details") = vbYes Then ActiveSheet.Range("Street") = VBA.Mid(sigRow(i), 1, SpaceInName)
    End If
    'Trim the Street, Number leaving the Suburb if its exists on the same line
    sigRow(i) = VBA.Mid(sigRow(i), SpaceInName) + 2
    sigRow(i) = Replace(sigRow(i), VBA.Mid(sigRow(i), 1, SpaceInName), "")

    GoTo PastAddress:
    End If
    Next j
End If
Next i
PastAddress:

'Mobile
For i = 1 To UBound(sigRow)
If Len(sigRow(i)) > 0 Then
    For j = 0 To 3
    Temp = Mb(j)
        If VBA.Left(VBA.UCase(sigRow(i)), Len(Temp)) = Temp Then
        If ActiveSheet.Shapes("chkConfirm").ControlFormat.Value = 0 Then
        ActiveSheet.Range("Mobile") = VBA.Mid(sigRow(i), Len(Temp) + 2)
        Else
          If MsgBox("Mobile: " & VBA.Mid(sigRow(i), Len(Temp) + 2), vbQuestion + vbYesNo, "Confirm Details") = vbYes Then ActiveSheet.Range("Mobile") = VBA.Mid(sigRow(i), Len(Temp) + 2)
        End If
    sigRow(i) = ""
    GoTo PastMobile:
    End If
    Next j
End If
Next i
PastMobile:

'Phone
For i = 1 To UBound(sigRow)
If Len(sigRow(i)) > 0 Then
    For j = 0 To 1
    Temp = Ph(j)
        If VBA.Left(VBA.UCase(sigRow(i)), Len(Temp)) = Temp Then

            'TODO: Detect the intl or national extension here.. or if we can from the postcode.
            If ActiveSheet.Shapes("chkConfirm").ControlFormat.Value = 0 Then
            ActiveSheet.Range("Phone") = VBA.Mid(sigRow(i), Len(Temp) + 3)
            Else
              If MsgBox("Phone: " & VBA.Mid(sigRow(i), Len(Temp) + 3), vbQuestion + vbYesNo, "Confirm Details") = vbYes Then ActiveSheet.Range("Phone") = VBA.Mid(sigRow(i), Len(Temp) + 3)
            End If

        sigRow(i) = ""
        GoTo PastPhone:
        End If
    Next j
End If
Next i
PastPhone:


'Email
For i = 1 To UBound(sigRow)
    If Len(sigRow(i)) > 0 Then
        'replace with regEx search
        If InStr(1, sigRow(i), "@", vbTextCompare) And InStr(1, VBA.UCase(sigRow(i)), ".CO", vbTextCompare) Then
        Dim email As String
        email = sigRow(i)
        email = Replace(VBA.UCase(email), "EMAIL:", "")
        email = Replace(VBA.UCase(email), "E-MAIL:", "")
        email = Replace(VBA.UCase(email), "E:", "")
        email = Replace(VBA.UCase(Trim(email)), "E ", "")
        email = VBA.LCase(email)

            If ActiveSheet.Shapes("chkConfirm").ControlFormat.Value = 0 Then
            ActiveSheet.Range("Email") = email
            Else
              If MsgBox("Email: " & email, vbQuestion + vbYesNo, "Confirm Details") = vbYes Then ActiveSheet.Range("Email") = email
            End If
        sigRow(i) = ""
        Exit For
        End If
    End If
Next i

'Now the only remaining items will be the postcode, suburb, country
'there shouldn't be any numbers (eg. from PoBox,Ph,Fax,Mobile) except for the Post Code

'Join the string and filter out the Post Code
Temp = Join(sigRow, vbCrLf)
Temp = Trim(Temp)

For i = 1 To Len(Temp)

Dim postCode As String
postCode = VBA.Mid(Temp, i, 4)

'In Australia PostCodes are 4 digits
If VBA.Mid(Temp, i, 1) <> " " And IsNumeric(postCode) Then

    If ActiveSheet.Shapes("chkConfirm").ControlFormat.Value = 0 Then
    ActiveSheet.Range("PostCode") = postCode
    Else
      If MsgBox("Post Code: " & postCode, vbQuestion + vbYesNo, "Confirm Details") = vbYes Then ActiveSheet.Range("PostCode") = postCode
    End If

    'Lookup the Suburb and State based on the PostCode, the PostCode sheet has the lookup
    Dim mySuburbArray As Range
    Set mySuburbArray = Sheets("PostCodes").Range("A2:B16670")

    Dim suburbs As String
    For j = 1 To mySuburbArray.Columns(1).Cells.Count
    If mySuburbArray.Cells(j, 1) = postCode Then
        'Check if the suburb is listed in the address
        If InStr(1, UCase(Temp), mySuburbArray.Cells(j, 2), vbTextCompare) > 0 Then

        'Set the Suburb and State
        ActiveSheet.Range("Suburb") = mySuburbArray.Cells(j, 2)
        Stat = mySuburbArray.Cells(j, 3)
        ActiveSheet.Range("State") = Stat

        'Knowing the State - for Australia we can get the telephone Ext
        PhExt = PhExtension(VBA.UCase(Stat))
        ActiveSheet.Range("PhExt") = PhExt

        'remove the phone extension from the number
        Dim prePhone As String
        prePhone = ActiveSheet.Range("Phone")
        prePhone = Replace(prePhone, PhExt & " ", "")
        prePhone = Replace(prePhone, "(" & PhExt & ") ", "")
        prePhone = Replace(prePhone, "(" & PhExt & ")", "")
        ActiveSheet.Range("Phone") = prePhone
        Exit For
        End If
    End If
    Next j
Exit For
End If
Next i

End Sub


Private Function PhExtension(ByVal State As String) As String
Select Case State
Case Is = "NSW"
PhExtension = "02"
Case Is = "QLD"
PhExtension = "07"
Case Is = "VIC"
PhExtension = "03"
Case Is = "NT"
PhExtension = "04"
Case Is = "WA"
PhExtension = "05"
Case Is = "SA"
PhExtension = "07"
Case Is = "TAS"
PhExtension = "06"
End Select
End Function

Private Function Ph(ByVal Num As Integer) As String
Select Case Num
Case Is = 0
Ph = "PH"
Case Is = 1
Ph = "PHONE"
'Case Is = 2
'Ph = "P"
End Select
End Function

Private Function Mb(ByVal Num As Integer) As String
Select Case Num
Case Is = 0
Mb = "MB"
Case Is = 1
Mb = "MOB"
Case Is = 2
Mb = "CELL"
Case Is = 3
Mb = "MOBILE"
'Case Is = 4
'Mb = "M"
End Select
End Function

Private Function Fax(ByVal Num As Integer) As String
Select Case Num
Case Is = 0
Fax = "FAX"
Case Is = 1
Fax = "FACSIMILE"
'Case Is = 2
'Fax = "F"
End Select
End Function

Private Function State(ByVal Num As Integer) As String
Select Case Num
Case Is = 0
State = "NSW"
Case Is = 1
State = "QLD"
Case Is = 2
State = "VIC"
Case Is = 3
State = "NT"
Case Is = 4
State = "WA"
Case Is = 5
State = "SA"
Case Is = 6
State = "TAS"
End Select
End Function

Private Function Street(ByVal Num As Integer) As String
Select Case Num
Case Is = 0
Street = " ST"
Case Is = 1
Street = " RD"
Case Is = 2
Street = " AVE"
Case Is = 3
Street = " AV"
Case Is = 4
Street = " CRES"
Case Is = 5
Street = " LOOP"
Case Is = 6
Street = "PO BOX"
Case Is = 7
Street = " STREET"
Case Is = 8
Street = " ROAD"
Case Is = 9
Street = " AVENUE"
Case Is = 10
Street = " CRESENT"
Case Is = 11
Street = " PARADE"
Case Is = 12
Street = " PDE"
Case Is = 13
Street = " LANE"
Case Is = 14
Street = " COURT"
Case Is = 15
Street = " BLVD"
Case Is = 16
Street = "P.O. BOX"
Case Is = 17
Street = "P.O BOX"
Case Is = 18
Street = "PO BOX"
Case Is = 19
Street = "POBOX"
End Select
End Function
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.