주소 파서는 하나의 문자열을 구조화된 필드로 변환합니다: line 1, line 2, city, region, postal code, country. 쉼표로 나누면 될 것 같지만, 우편번호가 도시보다 앞서는 독일 주소, 가장 큰 단위부터 쓰는 일본 주소, 또는 "St"가 거리 접미사가 아니라 도시 이름의 일부인 미국 주소를 만나면 이야기가 달라집니다.
이 가이드는 모호성에 대해 정직한 파서를 설명합니다. 설계 원칙은 간단합니다: 문법이 지원하는 것만 파싱하고, 파싱한 것에 점수를 매기며, 신뢰도가 낮으면 원본 문자열을 그대로 반환합니다. 잘못된 필드를 조용히 반환하는 파서는 거부하는 파서보다 나쁩니다. 잘못된 필드가 저장되고 원본은 버려지기 때문입니다.
파싱으로 복구할 수 있는 것과 없는 것
파싱은 텍스트에 존재했던 구조를 복구합니다: 우편번호, 지역 코드, 도시, 거리 줄 순으로 신뢰도가 높습니다. 기록되지 않은 정보는 복구할 수 없습니다. 호수 지정자가 없는 문자열에는 호수 번호가 없으며, 어떤 추론으로도 이를 만들어내서는 안 됩니다.
또한 필드가 사실인지 확인할 수 없습니다. "123 Main St, Springfield, IL 62701"을 파싱하면 일관된 필드가 나오지만, 그 주소는 여전히 허구일 수 있고 도시가 ZIP과 일치하지 않을 수도 있습니다. 파싱은 텍스트 작업입니다. 검증은 데이터 작업이며, 둘은 절대 같은 함수 이름이나 성공 메시지를 공유해서는 안 됩니다.
- 복구 가능: 우편번호, 지역, 도시, 거리 줄, 호수 지정자
- 복구 불가: 누락된 호수, 누락된 국가, 잘못된 도시
- 전화 접두사나 언어로 국가를 추론하지 말 것
- 빈 필드를 그럴듯한 기본값으로 채우지 말 것
4단계 파이프라인
1단계는 정규화입니다: 공백 제거, 내부 공백 축소, 줄바꿈 없는 공백 교체, 구두점 변형 정규화, 대문자화 여부 결정. 폴백을 위해 원본은 그대로 유지합니다. 2단계는 분할입니다: 쉼표가 있으면 쉼표로 나누고, 없으면 국가 문법으로 나눕니다. 3단계는 분류입니다: 국가 규칙 세트를 사용해 각 세그먼트를 postal, region, city, street, unit으로 레이블링합니다. 4단계는 할당입니다: 레이블을 필드에 매핑하고, 충돌을 해결하고, 결과에 점수를 매깁니다.
단계를 분리하면 실패 모드도 분리됩니다. 분할 버그는 분류 버그와 다르게 보이며, 각 단계는 자체 코퍼스로 단위 테스트할 수 있습니다. 또한 조기 중단도 가능합니다: 국가를 모르면 분류를 완전히 건너뛰고 각 필드 신뢰도를 unknown으로 표시한 세그먼트를 반환합니다.
- 원본을 훼손하지 않고 정규화
- 쉼표 우선, 문법 차선으로 분할
- 국가별 규칙 세트로 분류
- 할당 후 점수 매기고 수용 여부 결정
국가별 필드 순서
필드 순서는 잘못된 파싱의 가장 큰 원인입니다. 같은 토큰이 위치를 바꾸기 때문입니다. 미국, 캐나다, 영국, 호주는 도시 뒤에 우편번호를 둡니다. 독일, 프랑스, 네덜란드, 벨기에는 도시 앞에 둡니다. 일본은 도도부현 앞, 맨 처음에 둡니다. 브라질은 주 뒤에 구분자와 함께 우편번호를 둡니다.
그래서 파서는 무엇이든 분류하기 전에 국가를 알아야 합니다. 문자열 자체에서 국가를 추론하는 것은 순환 논리입니다: 우편 패턴이 하나를 시사할 수 있지만 많은 패턴이 겹칩니다. 양식, 로캘 또는 명시적 선택기에서 국가를 받고, 없으면 주나 국가일 수 있는 두 글자 토큰으로 추측하지 말고 파싱을 낮은 신뢰도로 표시하세요.
| 국가 | 순서 | 예시 |
|---|---|---|
| 미국 | 거리, 도시, ST ZIP | 1420 SW Alder St, Portland, OR 97205 |
| 캐나다 | 거리, 도시, ST A1A 1A1 | 88 Queen St W, Toronto, ON M5H 2M5 |
| 독일 | 거리, ZIP 도시 | Unter den Linden 77, 10117 Berlin |
| 프랑스 | 번호 거리, ZIP 도시 | 12 Rue de Rivoli, 75004 Paris |
| 네덜란드 | 거리 번호, ZIP 도시 | Damrak 1, 1012 LG Amsterdam |
| 일본 | ZIP, 도도부현, 도시, 거리 | 100-0001 Tokyo, Chiyoda, Chiyoda 1-1 |
| 브라질 | 거리, 도시 - ST, ZIP | Av. Paulista 1000, Sao Paulo - SP, 01310-100 |
처리할 가치가 있는 모호한 사례
보조 호수 지정자가 가장 흔한 모호성입니다. "Apt", "Ste", "Unit", "Fl", "Rm"은 식별자가 뒤따를 때 신뢰할 수 있지만, "Unit 5"는 거리 이름일 수도 있고 "Building 3"은 캠퍼스의 기본 주소일 수도 있습니다. 파서는 지정자 뒤에 숫자나 짧은 영숫자 토큰이 오고 거리 번호 뒤에 나타날 때만 호수를 추출해야 합니다.
거리 접미사가 두 번째 함정입니다. "Way", "Court", "Park" 같은 토큰은 접미사, 거리 이름, 도시가 될 수 있습니다. 방향어도 같은 문제가 있습니다: "N"은 전방향어, 거리 이름 약어, 지역이 될 수 있습니다. 집 번호와 쉼표 구조에 대한 상대적 위치를 사용하고, 두 해석이 모두 그럴듯하면 선택하지 말고 원본 세그먼트를 유지하며 신뢰도를 낮추세요.
| 입력 | 가능한 해석 | 안전한 처리 |
|---|---|---|
| 12 Court St | 거리 접미사 또는 이름의 일부 | 전체 거리 줄 유지 |
| Unit 5, 100 Main St | 거리 앞의 호수 | 호수 할당, 거리 유지 |
| 100 N Park Ave | 방향어와 접미사 | 거리 토큰을 순서대로 유지 |
| Springfield Rd, Springfield | 도시 이름 속 접미사 | 쉼표 경계 우선 |
| Tokyo, Chiyoda 1-1 | 도시와 블록 | 국가 문법 사용 |
| Apt 4B 12 Main | 쉼표 없는 호수 | 추출 후 재점수화 |
신뢰도 점수와 임계값
각 필드에 점수를 매긴 다음 레코드에 점수를 매깁니다. 필드는 고정된 국가 패턴과 일치하고 위치가 예상 순서와 일치하면 높은 신뢰도입니다. 패턴은 일치했지만 위치가 추론된 경우 중간, 소거법으로 할당된 경우 낮음입니다. 레코드는 모든 필수 필드가 높고 배치되지 않은 세그먼트가 없을 때만 높은 신뢰도입니다.
임계값을 설정하고 강제하세요. 임계값 이상이면 수용하고 저장합니다. 미만이면 원본 문자열을 유지하고 구조화된 컬럼에 추측을 쓰지 말고 검토용으로 플래그합니다. 검토자는 무엇이 실패했는지 알아야 하므로 API 응답에 점수와 이유를 노출하세요.
| 필드 | 높은 신뢰도 신호 | 낮은 신뢰도 신호 |
|---|---|---|
| 우편번호 | 고정된 일치, 올바른 위치 | 패턴은 일치했지만 이동됨 |
| 지역 | 해당 국가의 알려진 코드 | 일치하지 않는 두 글자 토큰 |
| 도시 | 우편번호 왼쪽 또는 거리 오른쪽 | 소거법으로 할당됨 |
| 거리 | 집 번호와 이름 포함 | 번호 없는 이름만 |
| 호수 | 거리 뒤 지정자와 식별자 | 거리 이름 내부의 지정자 |
반환해야 할 오류 상태
파싱 결과는 불리언이 아닌 명시적 결과를 가져야 합니다. 국가 누락은 문법을 실행할 수 없음을 의미합니다. 우편번호 누락은 우편번호가 있는 국가에서는 문제이고, 홍콩과 UAE에서는 정상입니다. 배치 불가 세그먼트는 쉼표 구조와 문법이 불일치하며 사람의 확인이 필요함을 의미합니다.
각 결과에 안정적인 코드를 부여해 호출자가 산문을 파싱하지 않고 분기할 수 있게 하세요. 정규화된 입력, 원본 입력, 신뢰도가 포함된 필드 값, 배치되지 않은 세그먼트 목록을 반환하세요. 이 페이로드로 UI는 양식 상단에 일반 오류를 표시하는 대신 실패한 정확한 토큰을 강조할 수 있습니다.
- MISSING_COUNTRY: 사용 가능한 문법 없음, 추측하지 말 것
- MISSING_POSTAL: 국가에 코드가 있으면 오류, 없으면 정상
- UNPLACED_SEGMENT: 쉼표로 구분된 부분이 어떤 필드와도 일치하지 않음
- AMBIGUOUS_UNIT: 하나 이상의 해석이 있는 호수 지정자
- REGION_MISMATCH: 제공된 국가에 유효하지 않은 지역 코드
골든 코퍼스 구축 및 변형
수작업으로 검증한 작은 코퍼스로 시작하세요. 국가당 1~3개의 주소, 각각 해당 국가의 우편물을 읽는 사람이 작성한 예상 필드 값을 포함합니다. 20~40개 사례면 구조적 회귀를 잡기에 충분하고 풀 리퀘스트에서 검토하기에도 충분히 작습니다. 테스트 코드에 묻힌 어서션이 아니라 데이터로 저장하세요.
그런 다음 각 사례를 기계적으로 변형하세요: 쉼표 제거, 대소문자 변경, 이중 공백 축소, 줄바꿈 없는 공백 삽입, 두 줄 교환, 접미사 약어화, 호수 추가. 변형에 대한 예상 출력이 항상 동일하지는 않지만 정의된 허용 범위 내에 있어야 하며, 필드가 조용히 바뀌는 대신 신뢰도가 떨어져야 합니다. 필드별 정밀도와 재현율을 추적해 도시 수정이 우편번호를 조용히 망가뜨리지 않도록 하세요.
| 변형 | 예시 변경 | 예상 동작 |
|---|---|---|
| 쉼표 제거 | 1420 SW Alder St Portland OR 97205 | 동일 필드, 낮은 신뢰도 |
| 소문자화 | portland, or 97205 | 정규화 후 동일 필드 |
| 이중 공백 | Portland, OR 97205 | 동일 필드, 공백 축소 |
| 도시와 주 사이 NBSP | Portland, OR with U+00A0 | 동일 필드, NBSP 정규화 |
| 도시와 지역 교환 | OR Portland 97205 | 플래그 표시, 조용히 교환하지 않음 |
| 거리 잘라내기 | 1420 SW Alder | 거리 유지, 도시 여전히 발견 |
파싱하지 말아야 할 때
자유 형식 메모, 배송 지시, 사람이 산문으로 쓴 것은 파싱하지 마세요. "Leave at the side gate, second house after the blue one"에는 필드가 없으며, 토큰을 추출하면 확신에 찬 쓰레기가 나옵니다. 주문에 첨부된 텍스트 덩어리로 유지하세요.
규칙 세트가 다루지 않는 문자 체계는 파싱하지 마세요. 한자로 된 일본 주소는 일본어 문법이 필요합니다. 라틴 문자 토크나이저를 실행하면 잘못된 경계에서 나뉘고 도도부현을 잃게 됩니다. 거리 번호가 없거나 아시아 일부와 캠퍼스 주소에서 흔한 건물 이름을 기본 위치 지정자로 사용하는 주소도 파싱하지 마세요. 이 모든 경우 올바른 출력은 원본 문자열과 명확한 "not parsed" 상태입니다.
- 배송 지시: 필드가 아닌 텍스트로 저장
- 지원되지 않는 문자 체계: 명시적 상태와 함께 원본 반환
- 건물 이름 주소: 집 번호를 강제하지 말 것
- PO Box와 시골 경로: 일반 규칙이 아닌 국가별 규칙으로 파싱
- 이미 구조화된 것: 재파싱 대신 검증
질문
- 아니요. 텍스트에 존재하는 구조를 복구하고 자체 신뢰도에 점수를 매깁니다. 기록되지 않은 필드는 복구할 수 없으며, 파싱은 주소가 실제임을 증명하지 않습니다.
- 필드 순서가 다릅니다: 독일과 일본은 도시 앞에 우편번호를 두고, 일본은 맨 처음, 미국은 맨 마지막에 둡니다. 국가 규칙 세트가 없으면 같은 토큰이 잘못된 필드에 할당됩니다.
- 원본 문자열을 유지하고, 점수와 함께 부분 필드를 반환하며, 검토용으로 레코드를 플래그합니다. 구조화된 컬럼에 추측을 쓰면 입력의 유일한 신뢰할 수 있는 사본을 잃게 됩니다.
- 국가당 1~3개씩 수작업으로 검증한 20~40개 사례와 기계적 변형이면 충분합니다. 아무도 검토하지 않는 코퍼스를 만들지 않고도 구조적 회귀를 잡을 수 있습니다.
- 주소 파서 도구는 필드 모델과 형식 규칙을 제공합니다. 배송 가능성을 검증하지 않으며, 파싱된 필드가 실제 위치를 설명한다고 주장하지 않습니다.
주소 파서가 올바른 필드를 보장할 수 있나요?+
파싱 전에 국가가 왜 중요한가요?+
신뢰도가 낮을 때 파서는 무엇을 해야 하나요?+
테스트 주소가 몇 개 필요한가요?+
사이트가 제 주소를 파싱해 주나요?+
예시는 합성 데이터입니다. 생성된 주소를 신원 확인, 계정 등록 또는 배송에 사용하지 마세요.