tr-adres 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. tr_adres-0.1.0/CHANGELOG.md +24 -0
  2. tr_adres-0.1.0/CITATION.cff +20 -0
  3. tr_adres-0.1.0/LICENSE +21 -0
  4. tr_adres-0.1.0/MANIFEST.in +10 -0
  5. tr_adres-0.1.0/PKG-INFO +315 -0
  6. tr_adres-0.1.0/README.md +277 -0
  7. tr_adres-0.1.0/pyproject.toml +123 -0
  8. tr_adres-0.1.0/setup.cfg +4 -0
  9. tr_adres-0.1.0/src/tr_adres/__init__.py +85 -0
  10. tr_adres-0.1.0/src/tr_adres/__main__.py +7 -0
  11. tr_adres-0.1.0/src/tr_adres/_sozluk.py +62 -0
  12. tr_adres-0.1.0/src/tr_adres/cli.py +160 -0
  13. tr_adres-0.1.0/src/tr_adres/data/gazetteer.json +1 -0
  14. tr_adres-0.1.0/src/tr_adres/formatter.py +96 -0
  15. tr_adres-0.1.0/src/tr_adres/gazetteer.py +349 -0
  16. tr_adres-0.1.0/src/tr_adres/metin.py +124 -0
  17. tr_adres-0.1.0/src/tr_adres/model.py +82 -0
  18. tr_adres-0.1.0/src/tr_adres/pandas_ext.py +62 -0
  19. tr_adres-0.1.0/src/tr_adres/parser.py +1021 -0
  20. tr_adres-0.1.0/src/tr_adres/py.typed +0 -0
  21. tr_adres-0.1.0/src/tr_adres.egg-info/PKG-INFO +315 -0
  22. tr_adres-0.1.0/src/tr_adres.egg-info/SOURCES.txt +35 -0
  23. tr_adres-0.1.0/src/tr_adres.egg-info/dependency_links.txt +1 -0
  24. tr_adres-0.1.0/src/tr_adres.egg-info/entry_points.txt +2 -0
  25. tr_adres-0.1.0/src/tr_adres.egg-info/requires.txt +9 -0
  26. tr_adres-0.1.0/src/tr_adres.egg-info/top_level.txt +1 -0
  27. tr_adres-0.1.0/tests/blind.py +248 -0
  28. tr_adres-0.1.0/tests/corpus.py +580 -0
  29. tr_adres-0.1.0/tests/test_cli.py +147 -0
  30. tr_adres-0.1.0/tests/test_corpus.py +38 -0
  31. tr_adres-0.1.0/tests/test_doctests.py +33 -0
  32. tr_adres-0.1.0/tests/test_formatter.py +81 -0
  33. tr_adres-0.1.0/tests/test_gazetteer.py +193 -0
  34. tr_adres-0.1.0/tests/test_metin.py +110 -0
  35. tr_adres-0.1.0/tests/test_pandas.py +48 -0
  36. tr_adres-0.1.0/tests/test_parser.py +104 -0
  37. tr_adres-0.1.0/tools/build_gazetteer.py +119 -0
@@ -0,0 +1,24 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [0.1.0] - 2026-11-08
8
+ ### Added
9
+ - `parse(text) -> Adres`: rule-based parser for free-text Turkish postal addresses: il, ilçe,
10
+ mahalle, köy, cadde/bulvar/yol/meydan and sokak/çıkmaz (with type), site, apartman, blok,
11
+ bina no, kat, iç kapı/daire no, posta kodu, plus `confidence`, the unparsed remainder
12
+ (`kalan`) and a list of corrections and inferences (`notlar`).
13
+ - Abbreviations (`mah. mh. cad. cd. sok. sk. bulv. blv. no: d: k: kat apt. blk. sit.` …),
14
+ Turkish casing, ASCII-folded input, typo-tolerant province/district matching (bounded
15
+ Damerau-Levenshtein), arbitrary component order, `No:12/3` building/flat numbers,
16
+ numbered streets (`1203/2 Sk.`), floors and blocks, labelled forms, postal codes.
17
+ - `normalize(text)` and `format(adres, style="kargo"|"resmi")`.
18
+ - Gazetteer of all 81 provinces with plate codes and 973 districts with PTT postal-code
19
+ ranges (`il_bul`, `ilce_bul`, `ilce_ara`, `plaka`, `is_valid_ilce`, `merkez_ilce`,
20
+ `posta_kodu_il`, `posta_kodu_ilceler`, `iller`, `ilceler`, `kaynak`).
21
+ - Turkish string helpers: `tr_lower`, `tr_upper`, `tr_title`, `ascii_fold`, `edit_distance`.
22
+ - `parse_many` and the `tr-adres` command (`parse` / `normalize`, text, stdin or CSV in →
23
+ CSV out).
24
+ - Optional pandas accessor `Series.tradres` (`pip install "tr-adres[pandas]"`).
@@ -0,0 +1,20 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use this software, please cite it as below."
3
+ authors:
4
+ - family-names: "Eminoğlu"
5
+ given-names: "Yusuf"
6
+ email: "yusufeminoglu@gmail.com"
7
+ orcid: "https://orcid.org/0009-0005-6000-2934"
8
+ title: "tr-adres"
9
+ version: "0.1.0"
10
+ date-released: "2026-11-08"
11
+ license: "MIT"
12
+ repository-code: "https://github.com/YusufEminoglu/tr_adres_sdk"
13
+ url: "https://pypi.org/project/tr-adres/"
14
+ abstract: "Parser and normaliser for Turkish postal addresses with a bundled gazetteer of the 81 provinces and 973 districts of Türkiye."
15
+ keywords:
16
+ - turkish
17
+ - address parsing
18
+ - address normalization
19
+ - gazetteer
20
+ - data cleaning
tr_adres-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Yusuf Eminoğlu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,10 @@
1
+ include LICENSE
2
+ include README.md
3
+ include CHANGELOG.md
4
+ include CITATION.cff
5
+ include pyproject.toml
6
+ include src/tr_adres/py.typed
7
+ recursive-include src/tr_adres *.py
8
+ recursive-include src/tr_adres/data *.json
9
+ recursive-include tests *.py
10
+ recursive-include tools *.py
@@ -0,0 +1,315 @@
1
+ Metadata-Version: 2.4
2
+ Name: tr-adres
3
+ Version: 0.1.0
4
+ Summary: Parse and normalise Turkish postal addresses: il, ilçe, mahalle, street, building and flat numbers, with a bundled gazetteer of all 81 provinces and 973 districts.
5
+ Author-email: Yusuf Eminoğlu <yusufeminoglu@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/YusufEminoglu/tr_adres_sdk
8
+ Project-URL: Repository, https://github.com/YusufEminoglu/tr_adres_sdk
9
+ Project-URL: Issues, https://github.com/YusufEminoglu/tr_adres_sdk/issues
10
+ Project-URL: Changelog, https://github.com/YusufEminoglu/tr_adres_sdk/blob/main/CHANGELOG.md
11
+ Keywords: turkish,turkey,turkiye,address,address-parser,address-normalization,adres,il,ilce,mahalle,postal-code,posta-kodu,gazetteer,geocoding,data-cleaning,logistics,e-commerce,nlp
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Operating System :: OS Independent
20
+ Classifier: Natural Language :: Turkish
21
+ Classifier: Topic :: Text Processing :: Linguistic
22
+ Classifier: Topic :: Scientific/Engineering :: GIS
23
+ Classifier: Topic :: Office/Business
24
+ Classifier: Intended Audience :: Developers
25
+ Classifier: Intended Audience :: Science/Research
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.9
28
+ Description-Content-Type: text/markdown
29
+ License-File: LICENSE
30
+ Provides-Extra: pandas
31
+ Requires-Dist: pandas>=1.3.0; extra == "pandas"
32
+ Provides-Extra: dev
33
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
34
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
35
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
36
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
37
+ Dynamic: license-file
38
+
39
+ # tr-adres
40
+
41
+ [![PyPI](https://img.shields.io/pypi/v/tr-adres.svg)](https://pypi.org/project/tr-adres/)
42
+ [![Python](https://img.shields.io/pypi/pyversions/tr-adres.svg)](https://pypi.org/project/tr-adres/)
43
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
44
+
45
+ **Türkçe posta adreslerini ayrıştırma ve standartlaştırma kütüphanesi** · *Parse and normalise
46
+ Turkish postal addresses* — saf Python, bağımlılıksız, 81 il ve 973 ilçelik gömülü sözlükle.
47
+
48
+ ```python
49
+ >>> import tr_adres
50
+ >>> tr_adres.normalize("caferaga mh moda cd no 12 d 3 kadikoy istanbul")
51
+ 'Caferağa Mah. Moda Cad. No:12 D:3 Kadıköy/İstanbul'
52
+
53
+ ```
54
+
55
+ [Türkçe](#türkçe) · [English](#english)
56
+
57
+ ---
58
+
59
+ ## Türkçe
60
+
61
+ E-ticaret ödeme formları, kargo etiketleri ve CRM kayıtlarındaki serbest metin adresleri
62
+ bileşenlerine ayırır (il, ilçe, mahalle, cadde/sokak, bina no, kat, daire, site/apartman/blok,
63
+ posta kodu), yazım hatalarını ve ASCII yazımı düzeltir, tek satırlık standart biçime çevirir.
64
+
65
+ ### Kurulum
66
+
67
+ ```bash
68
+ pip install tr-adres # yalnızca standart kütüphane
69
+ pip install "tr-adres[pandas]" # pandas eklentisiyle
70
+ ```
71
+
72
+ Python 3.9+ gerekir. Çalışma zamanı bağımlılığı yoktur.
73
+
74
+ ### Hızlı başlangıç
75
+
76
+ ```python
77
+ >>> from tr_adres import parse
78
+ >>> a = parse("caferaga mh. moda cd. no:12/3 kadikoy")
79
+ >>> a.mahalle, a.cadde, a.cadde_tipi, a.bina_no, a.daire_no
80
+ ('Caferağa', 'Moda', 'Cadde', '12', '3')
81
+ >>> a.ilce, a.il, a.il_plaka
82
+ ('Kadıköy', 'İstanbul', 34)
83
+ >>> a.notlar
84
+ ['il, ilçeden çıkarıldı: İstanbul']
85
+ >>> str(a)
86
+ 'Caferağa Mah. Moda Cad. No:12 D:3 Kadıköy/İstanbul'
87
+ >>> tr_adres.format(a, style="resmi")
88
+ 'Caferağa Mahallesi, Moda Caddesi, No: 12, İç Kapı No: 3, Kadıköy/İSTANBUL'
89
+
90
+ ```
91
+
92
+ ### Önce / sonra
93
+
94
+ | Girdi | `normalize()` çıktısı |
95
+ |---|---|
96
+ | `caferaga mh moda cd no 12 d 3 kadikoy istanbul` | `Caferağa Mah. Moda Cad. No:12 D:3 Kadıköy/İstanbul` |
97
+ | `ISTANBUL BESIKTAS LEVENT MAH. BUYUKDERE CAD NO 185` | `Levent Mah. Büyükdere Cad. No:185 Beşiktaş/İstanbul` |
98
+ | `Kızılay Mah. Atatürk Bulvarı No:115 Kat:4 Çankaya/ANKARA` | `Kızılay Mah. Atatürk Bulv. No:115 K:4 Çankaya/Ankara` |
99
+ | `alsancak mah 1469 sk no 8 d 2 konak izmir` | `Alsancak Mah. 1469 Sk. No:8 D:2 Konak/İzmir` |
100
+ | `Bağdat Caddesi No:350 Daire:12 Kat:5 Suadiye Mahallesi Kadıköy İstanbul 34740` | `Suadiye Mah. Bağdat Cad. No:350 K:5 D:12 34740 Kadıköy/İstanbul` |
101
+ | `Yıldız Sit. B Blk. Kat 2 D:5, Çankaya / ANKARA` | `Yıldız Sitesi B Blok K:2 D:5 Çankaya/Ankara` |
102
+ | `Kadikoy Caferaga Mah Moda Cad 12/3` | `Caferağa Mah. Moda Cad. No:12 D:3 Kadıköy/İstanbul` |
103
+ | `Levent Mah. Büyükdere Cad. No:185 Besiktas/Istnbul` | `Levent Mah. Büyükdere Cad. No:185 Beşiktaş/İstanbul` |
104
+ | `Afyon Merkez Dumlupınar Mah. Kurtuluş Cad. No:7` | `Dumlupınar Mah. Kurtuluş Cad. No:7 Afyonkarahisar/Afyonkarahisar` |
105
+ | `Mahalle: Caferağa, Cadde: Moda, No: 5, İlçe: Kadıköy, İl: İstanbul` | `Caferağa Mah. Moda Cad. No:5 Kadıköy/İstanbul` |
106
+ | `Bostanlı Mah. 1203/2 Sk. No:6 D:3 Karşıyaka İzmir` | `Bostanlı Mah. 1203/2 Sk. No:6 D:3 Karşıyaka/İzmir` |
107
+ | `Caferağa Mah. Moda Cad. No:12 Migros karşısı Kadıköy` | `Caferağa Mah. Moda Cad. No:12 Migros karşısı Kadıköy/İstanbul` |
108
+ | `Moda Cad. No:5 34710` | `Moda Cad. No:5 34710 Kadıköy/İstanbul` |
109
+ | `100. Yıl Mah. 29 Ekim Cad. No:4 Bağlar/Diyarbakır` | `100. Yıl Mah. 29 Ekim Cad. No:4 Bağlar/Diyarbakır` |
110
+ | `Cumhuriyet Mah. Gazi Cad. No:15-A Kat: Zemin Bayraklı İzmir` | `Cumhuriyet Mah. Gazi Cad. No:15/A K:Zemin Bayraklı/İzmir` |
111
+ | `Hayrullah Mah. Trabzon Cad. No:20 Onikişubat/K.Maraş` | `Hayrullah Mah. Trabzon Cad. No:20 Onikişubat/Kahramanmaraş` |
112
+
113
+ `style="resmi"` her türü açık yazar ve ili büyük harfle verir:
114
+ `Suadiye Mahallesi, Bağdat Caddesi, No: 350, Kat: 5, İç Kapı No: 12, 34740 Kadıköy/İSTANBUL`.
115
+
116
+ ### Neleri tanır?
117
+
118
+ - **Kısaltmalar**: `mah. mh. mahallesi`, `cad. cd. caddesi`, `sok. sk. sokak sokağı`,
119
+ `bulv. blv. bulvarı`, `yolu`, `meydanı`, `çıkmazı`, `no: no numara #`, `d: daire iç kapı no`,
120
+ `k: kat`, `apt. ap. apartmanı`, `sit. sitesi konutları evleri rezidans`, `plaza`,
121
+ `iş merkezi`, `iş hanı`, `blk. bl. blok`, `köyü`, `pk posta kodu`; tek harflik yazım hatası
122
+ (`Mahalesi`, `Cadesi`) da kabul edilir.
123
+ - **Numaralar**: `No:12/3` (bina 12, daire 3), `No:15/A`, `No:15A`, `No:15-A`, `3. Kat`,
124
+ `Zemin Kat`, `Kat:-1`, `B2 Blok`, `Blok: A-1`, anahtar sözcüksüz `Moda Cad. 12/3`.
125
+ - **Sıra ve ayraçlar**: bileşenler herhangi bir sırada, virgüllü/virgülsüz, `/ - ; |` ya da
126
+ satır sonlarıyla ayrılmış olabilir. `İstanbul Kadıköy Caferağa Mah.` gibi bitişik yazılan il
127
+ ve ilçe mahalle adından ayrılır.
128
+ - **Türkçe büyük/küçük harf**: `İ/i` ve `I/ı` doğru dönüştürülür (`tr_lower`, `tr_upper`,
129
+ `tr_title`). Tamamen ASCII yazılmış girdide (`Kadikoy`, `BUYUKDERE`) il/ilçe adları ve sık
130
+ kullanılan sözcükler Türkçe yazımlarına geri döndürülür.
131
+ - **Yazım hataları**: il ve ilçe adları küçük bir düzenleme uzaklığıyla (Damerau-Levenshtein,
132
+ 4–7 harfte 1, 8+ harfte 2) eşleştirilir: `Istnbul`, `Besiktas`, `Cankya`, `Ankra`, `Diyarbakr`.
133
+ - **Tutarlılık**: il ile ilçe her zaman birbiriyle uyumludur (`Maltepe Çankaya/Ankara` →
134
+ Maltepe İstanbul'da olduğu için kalan metne bırakılır). Tek ilde bulunan ilçeden il, posta
135
+ kodunun ilk iki hanesinden (plaka) il çıkarılır; çok illi ilçe adları (`Yenişehir`) posta
136
+ koduyla netleşir. `Merkez/Kütahya` → ilçe Kütahya.
137
+ - **Takma adlar**: `Afyon`, `K.Maraş`, `Urfa`, `Antep`, `İçel`, `İST`, `Eyüp`, `Kazan`,
138
+ `Karadeniz Ereğli`…
139
+
140
+ ### API
141
+
142
+ | İşlev | Açıklama |
143
+ |---|---|
144
+ | `parse(text) -> Adres` | Adresi ayrıştırır |
145
+ | `parse_many(iterable) -> list[Adres]` | Toplu ayrıştırma (`None`/NaN boş sonuç verir) |
146
+ | `normalize(text, style="kargo") -> str` | Standart tek satır |
147
+ | `format(adres, style="kargo"\|"resmi", include_remainder=True)` | `Adres`'i (ya da metni) biçimler |
148
+ | `il_bul(ad_veya_plaka)`, `ilce_bul(ad, il=None)`, `ilce_ara(ad, il=None)` | Sözlük araması |
149
+ | `plaka(il)`, `is_valid_ilce(il, ilce)`, `merkez_ilce(il)` | Plaka ve doğrulama |
150
+ | `posta_kodu_il(kod)`, `posta_kodu_ilceler(kod)` | Posta kodundan il/ilçe |
151
+ | `iller()`, `ilceler(il=None)`, `kaynak()` | Tüm liste ve veri kaynağı |
152
+ | `tr_lower`, `tr_upper`, `tr_title`, `ascii_fold`, `edit_distance` | Metin yardımcıları |
153
+
154
+ `Adres` alanları: `il, ilce, mahalle, koy, cadde, cadde_tipi (Cadde/Bulvar/Yol/Meydan),
155
+ sokak, sokak_tipi (Sokak/Çıkmaz), site, apartman, blok, bina_no, kat, daire_no, posta_kodu,
156
+ il_plaka, confidence (0–1), kalan (ayrıştırılamayan metin), notlar (düzeltme ve uyarılar),
157
+ girdi`; ayrıca `to_dict()`, `yol` ve `gecerli` özellikleri.
158
+
159
+ ```python
160
+ >>> from tr_adres import il_bul, ilce_bul, ilce_ara, plaka, is_valid_ilce, tr_upper
161
+ >>> il_bul("Urfa").ad, il_bul(6).ad, plaka("İzmir")
162
+ ('Şanlıurfa', 'Ankara', 35)
163
+ >>> [str(i) for i in ilce_ara("Yenişehir")]
164
+ ['Yenişehir/Bursa', 'Yenişehir/Diyarbakır', 'Yenişehir/Mersin']
165
+ >>> is_valid_ilce("istanbul", "KADIKOY"), is_valid_ilce("Ankara", "Kadıköy")
166
+ (True, False)
167
+ >>> tr_upper("istanbul ığdır"), "istanbul ığdır".upper()
168
+ ('İSTANBUL IĞDIR', 'ISTANBUL IĞDIR')
169
+
170
+ ```
171
+
172
+ ### Komut satırı
173
+
174
+ ```bash
175
+ tr-adres parse "Caferağa Mah. Moda Cad. No:12/3 Kadıköy/İstanbul" # JSON
176
+ tr-adres normalize "caferaga mh moda cd no 12 kadikoy" # tek satır
177
+ tr-adres normalize musteriler.csv --column adres -o temiz.csv # adres_normalize sütunu eklenir
178
+ tr-adres parse musteriler.csv --column adres -o ayrik.csv # adres_il, adres_ilce, ... sütunları
179
+ tr-adres normalize musteriler.csv -o temiz.csv --output-encoding utf-8-sig # Excel için BOM
180
+ cat adresler.txt | tr-adres normalize - # satır satır
181
+ ```
182
+
183
+ CSV ayırıcısı (`,` `;` sekme `|`) otomatik algılanır; girdi kodlaması varsayılan olarak
184
+ `utf-8-sig`'dir. `--style resmi`, `--prefix`, `--output-column`, `--delimiter` seçenekleri
185
+ vardır.
186
+
187
+ ### pandas
188
+
189
+ ```python
190
+ import pandas as pd
191
+ import tr_adres.pandas_ext # ya da: pandas'tan sonra `import tr_adres`
192
+
193
+ df = pd.read_csv("musteriler.csv")
194
+ parcalar = df["adres"].tradres.parse() # il, ilce, mahalle, ... sütunlu DataFrame
195
+ df["adres_temiz"] = df["adres"].tradres.normalize()
196
+ ```
197
+
198
+ ### Veri kaynağı
199
+
200
+ - **İl ve ilçe adları**: T.C. İçişleri Bakanlığı, *Mülki İdare Bölümleri Envanteri* — 81 il,
201
+ 973 ilçe. Liste, bu envanteri kaynak gösteren Türkçe Vikipedi tablosundan
202
+ ("Türkiye'nin ilçeleri", revizyon 37373921, erişim 2026-11-08) derlenmiştir. Zonguldak'taki
203
+ ilçe, makale başlığı "Karadeniz Ereğli" yerine resmî adıyla **Ereğli** olarak kaydedilmiştir
204
+ (eski ad takma ad olarak tanınır).
205
+ - **Plaka kodları**: kanunla belirlenmiş 01–81.
206
+ - **Posta kodları**: PTT posta kodu sorgusundan, her ilçe için en küçük–en büyük aralık.
207
+ İlk iki hanesi plakayla çelişen 5 kayıt (Kemalpaşa/Artvin, Baklan, Yağlıdere, Menderes,
208
+ Arpaçay) atılmıştır; bu ilçelerde posta kodu aralığı boştur.
209
+ - Veri `src/tr_adres/data/gazetteer.json` içinde (~30 KB) paketle gelir;
210
+ `tools/build_gazetteer.py` sabitlenmiş revizyondan yeniden üretir. Bunlar resmî idari
211
+ adlar ve kodlardır; kaynak gösterilmesi için `tr_adres.kaynak()` kullanılabilir.
212
+
213
+ ### Doğruluk
214
+
215
+ Testlerde üç ayrı, tamamen sentetik (gerçek kişi ya da teslimat adresi içermeyen) derlem vardır;
216
+ her alan (il, ilçe, mahalle, cadde+tipi, sokak+tipi, site, apartman, blok, bina, kat, daire,
217
+ posta kodu, kalan) birebir karşılaştırılır:
218
+
219
+ | Derlem | Adres | İlk çalıştırma | Şu an |
220
+ |---|---|---|---|
221
+ | Geliştirme (`tests/corpus.py`) | 191 | 191/191 tam (bir beklenti düzeltildi) | 191/191 |
222
+ | Ayrılmış (`HELD_OUT`) | 40 | 40/40 tam | 40/40 |
223
+ | Kör (`tests/blind.py`, uygulamaya bakmadan ayrı yazıldı) | 60 | **53/60 tam, alan doğruluğu %98,9** | 60/60 |
224
+
225
+ Kör derlemdeki 7 hatadan 5'i düzeltildi, 2'si beklenti farkıydı ("Merkez" ilçesini merkez
226
+ ilçenin adına çevirme kuralı). İlk çalıştırma sonuçları dürüst tahmindir; derlemler
227
+ geliştirmede kullanıldığı için "şu an" sütunu genelleme göstermez. Gerçek veride doğruluk,
228
+ yazım biçimine göre daha düşük olabilir.
229
+
230
+ ### Sınırlamalar
231
+
232
+ - **Mahalle doğrulanmaz.** Açık lisanslı, güncel bir mahalle listesi bulunamadığından mahalle
233
+ yalnızca `Mah./Mahallesi` anahtar sözcüğüyle tanınır ve bir ilçeye ait olup olmadığı
234
+ denetlenmez. Anahtar sözcüksüz yazılan semt/mahalle adları (`Moda`, `Ulus`) `kalan`'a düşer.
235
+ - **Aksan geri yükleme sınırlıdır.** ASCII girdide yalnızca il/ilçe adları ve küçük bir sık
236
+ sözcük listesi düzeltilir; `Kayabasi` gibi diğer adlar olduğu gibi kalır.
237
+ - **ASCII büyük harf**: Türkçe karakter içermeyen girdide `I` → `i` kabul edilir
238
+ (`BILGI` → `Bilgi`); Türkçe karakter içeren girdide `I` noktasızdır (`KIZILIRMAK` →
239
+ `Kızılırmak`).
240
+ - **Bulanık ilçe eşleşmesi** yalnızca il ya da posta koduyla doğrulanırsa kabul edilir
241
+ (`Göztepe`, Kırşehir'in `Boztepe` ilçesine 1 harf uzaktadır).
242
+ - **Posta kodu aralıkları** büyükşehirlerde örtüşür; ilçe yalnızca kod tek bir ilçenin
243
+ aralığına düşüyorsa çıkarılır.
244
+ - Mahalle adının başındaki il/ilçe adı ayrılır; ilçe başka yerde yazılmamışsa
245
+ `Fatih Sultan Mehmet Mah.` gibi bir ad yine doğru kalır (`Sultan`, `Paşa`, `Bey`... sonrası
246
+ bölünmez), ama her olası çakışma önlenemez.
247
+ - `confidence` sezgiseldir (bulunan bileşenler, düzeltmeler, çıkarımlar ve kalan sözcükler);
248
+ olasılık değildir. Saniyede yaklaşık 1000 adres işlenir (tek çekirdek).
249
+ - Kural tabanlıdır: posta kutusu, yurt dışı ve serbest tarif adresleri ("caminin arkası")
250
+ kapsam dışıdır.
251
+
252
+ ---
253
+
254
+ ## English
255
+
256
+ `tr-adres` turns free-text Turkish addresses from checkout forms, shipping labels and CRM
257
+ exports into structured fields and a canonical one-line form. Pure Python, no runtime
258
+ dependencies, ships a gazetteer of all **81 provinces (il) with plate codes and 973 districts
259
+ (ilçe)** with PTT postal-code ranges.
260
+
261
+ ```python
262
+ >>> import tr_adres
263
+ >>> a = tr_adres.parse("ISTANBUL BESIKTAS LEVENT MAH. BUYUKDERE CAD NO 185")
264
+ >>> a.il, a.ilce, a.mahalle, a.cadde, a.bina_no
265
+ ('İstanbul', 'Beşiktaş', 'Levent', 'Büyükdere', '185')
266
+ >>> tr_adres.normalize("Kızılay Mah. Atatürk Bulvarı No:115 Kat:4 Çankaya/ANKARA", style="resmi")
267
+ 'Kızılay Mahallesi, Atatürk Bulvarı, No: 115, Kat: 4, Çankaya/ANKARA'
268
+
269
+ ```
270
+
271
+ **What it handles**: all common abbreviations (`mah. mh. cad. cd. sok. sk. bulv. blv. no: d:
272
+ k: kat apt. ap. blk. sit.` …), Turkish casing (`İ/i`, `I/ı` — `tr_lower`, `tr_upper`,
273
+ `tr_title`), ASCII-folded input (`Kadikoy` → Kadıköy), typos in province/district names
274
+ (bounded Damerau-Levenshtein), arbitrary component order, missing commas, `/` separators
275
+ (`No:12/3` = building 12, flat 3), İzmir-style numbered streets (`1203/2 Sk.`), floors
276
+ (`3. Kat`, `Zemin Kat`, `Kat:-1`), blocks (`B2 Blok`), labelled forms (`İl: … İlçe: …`),
277
+ postal codes (province from the first two digits, district from PTT ranges when unambiguous),
278
+ and colloquial names (`Afyon`, `K.Maraş`, `Urfa`, `Antep`, `İçel`). Province and district are
279
+ always mutually consistent; a district that does not belong to the province is left in the
280
+ remainder. Anything not understood goes to `kalan`, and every correction or inference is
281
+ recorded in `notlar`.
282
+
283
+ **API** — `parse`, `parse_many`, `normalize`, `format(adres, style="kargo"|"resmi")`,
284
+ `il_bul`, `ilce_bul`, `ilce_ara`, `plaka`, `is_valid_ilce`, `merkez_ilce`, `posta_kodu_il`,
285
+ `posta_kodu_ilceler`, `iller`, `ilceler`, `kaynak`, `tr_lower`, `tr_upper`, `tr_title`,
286
+ `ascii_fold`, `edit_distance`. See the Turkish section above for the field list.
287
+
288
+ **CLI** — `tr-adres parse "…"` prints JSON; `tr-adres normalize file.csv --column adres -o
289
+ out.csv` adds an `adres_normalize` column (`tr-adres parse file.csv` adds `adres_il`,
290
+ `adres_ilce`, …). Delimiters are sniffed; use `--output-encoding utf-8-sig` for Excel.
291
+
292
+ **pandas** — `pip install "tr-adres[pandas]"`, then `import tr_adres.pandas_ext` (or import
293
+ `tr_adres` after pandas) and use `df["adres"].tradres.parse()` / `.normalize()`.
294
+
295
+ **Data** — district names from the Ministry of Interior inventory (via the Turkish Wikipedia
296
+ table that cites it, pinned revision 37373921), plate codes 01–81, PTT postal-code envelopes;
297
+ counts verified by the test suite (81 / 973, unique plates). The Zonguldak district is stored
298
+ under its official name *Ereğli* ("Karadeniz Ereğli" is accepted as an alias).
299
+
300
+ **Accuracy** — on a blind, synthetic 60-address set written without access to the code, the
301
+ first run scored 53/60 fully correct addresses and 98.9 % field accuracy; all three test
302
+ corpora (291 addresses) now pass. These are synthetic addresses, so expect lower accuracy on
303
+ real-world data.
304
+
305
+ **Limitations** — neighbourhoods (mahalle) are recognised by keyword only and are *not*
306
+ validated (no permissively licensed mahalle list was available); diacritics are restored for
307
+ province/district names and a small common-word list only; in all-ASCII input `I` is read as
308
+ `i`; a typo-matched district is accepted only when confirmed by the province or the postal
309
+ code; postal-code ranges overlap in metropolitan areas; `confidence` is a heuristic score,
310
+ not a probability. Throughput is about 1,000 addresses per second on one core.
311
+
312
+ ## Lisans / License
313
+
314
+ MIT © Yusuf Eminoğlu. Bkz. / see [LICENSE](LICENSE) ve atıf için / and for citation
315
+ [CITATION.cff](CITATION.cff).