[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Maposmatic-dev] [PATCH] Russian street name normal izer: i18n_ru_generi
From: |
Konstantin Mochalov |
Subject: |
[Maposmatic-dev] [PATCH] Russian street name normal izer: i18n_ru_generic.user_readable_street , using table of status parts from streetmangler proje ct |
Date: |
Fri, 11 May 2012 17:44:10 +0400 |
---
ocitysmap/i18n.py | 78 +++++++++++++++++++++++++++++++++++++++++-------
ocitysmap/i18n_test.py | 40 ++++++++++++++++++++++++
2 files changed, 107 insertions(+), 11 deletions(-)
create mode 100644 ocitysmap/i18n_test.py
diff --git a/ocitysmap/i18n.py b/ocitysmap/i18n.py
index d476717..3521b64 100644
--- a/ocitysmap/i18n.py
+++ b/ocitysmap/i18n.py
@@ -457,18 +457,53 @@ class i18n_ar_generic(i18n):
return True
class i18n_ru_generic(i18n):
- APPELLATIONS = [ u"ул", u"бул", u"пер", u"пр", u"улица", u"бульвар",
u"проезд",
- u"проспект", u"площадь", u"сквер", u"парк" ]
- # only "ул." and "пер." are recommended shortenings, however other words
can
- # occur shortened.
- #
- # http://bit.ly/6ASISp (OSM wiki)
- #
+ # Based on list from Streetmangler:
+ # https://github.com/AMDmi3/streetmangler/blob/master/lib/locales/ru.cc
+ STATUS_PARTS = [
+ (u"улица", [u"ул"]),
+ (u"площадь", [u"пл"]),
+ (u"переулок", [u"пер", u"пер-к"]),
+ (u"проезд", [u"пр-д"]),
+ (u"шоссе", [u"ш"]),
+ (u"бульвар", [u"бул", u"б-р"]),
+ (u"тупик", [u"туп"]),
+ (u"набережная", [u"наб"]),
+ (u"проспект", [u"просп", u"пр-кт", u"пр-т"]),
+ (u"линия", []),
+ (u"аллея", []),
+ (u"метромост", []),
+ (u"мост", []),
+ (u"просек", []),
+ (u"просека", []),
+ (u"путепровод", []),
+ (u"тракт", [u"тр-т", u"тр"]),
+ (u"тропа", []),
+ (u"туннель", []),
+ (u"тоннель", []),
+ (u"эстакада", [u"эст"]),
+ (u"дорога", [u"дор"]),
+ (u"спуск", []),
+ (u"подход", []),
+ (u"подъезд", []),
+ (u"съезд", []),
+ (u"заезд", []),
+ (u"разъезд", []),
+ (u"слобода", []),
+ (u"район", [u"р-н"]),
+ (u"микрорайон", [u"мкр-н", u"мк-н", u"мкр", u"мкрн"]),
+ (u"посёлок", [u"поселок", u"пос"]),
+ (u"деревня", [u"дер", u"д"]),
+ (u"квартал", [u"кв-л", u"кв"]),
+ ]
SPACE_REDUCE = re.compile(r"\s+")
- PREFIX_REGEXP = re.compile(r"^(?P<prefix>(%s)\.?)\s?\b(?P<name>.+)" %
- ("|".join(APPELLATIONS)), re.IGNORECASE
- | re.UNICODE)
+ STATUS_PARTS_MAPPING = dict((f, t) for t, ff in STATUS_PARTS for f in ff)
+ STATUS_REGEXP = re.compile(r"\b(%s)\.?(?=\W|$)" % u"|".join(
+ f for t, ff in STATUS_PARTS for f in ff), re.IGNORECASE | re.UNICODE)
+ PREFIX_REGEXP = re.compile(
+
ur"^(?P<num_prefix>\d+-?(ы?й|я))?\s*(?P<prefix>(%s)\.?)?\s*(?P<name>.+)?" %
+ (u"|".join(f for f,t in STATUS_PARTS)), re.IGNORECASE | re.UNICODE)
+ STARTING_NUMBER_REGEXP =
re.compile(ur"^(?P<prefix>\d+-?(ы?й|я))\s+(?P<name>.+)")
def __init__(self, language, locale_path):
self.language = str(language)
@@ -482,10 +517,31 @@ class i18n_ru_generic(i18n):
def language_code(self):
return self.language
+ @staticmethod
+ def _rewrite_street_parts(matches):
+ if matches.group('num_prefix') is None and matches.group('prefix') is
None:
+ return matches.group(0)
+ elif matches.group('name') is None:
+ return matches.group(0)
+ else:
+ #print matches.group('num_prefix', 'prefix', 'name')
+ return ", ".join((matches.group('name'),
+ " ". join(s.lower()
+ for s in matches.group('prefix', 'num_prefix')
+ if s is not None)
+ ))
+
def user_readable_street(self, name):
name = name.strip()
name = self.SPACE_REDUCE.sub(" ", name)
- name = self.PREFIX_REGEXP.sub(r"\g<name> (\g<prefix>)", name)
+ # Normalize abbreviations
+ name = self.STATUS_REGEXP.sub(lambda m:
+ self.STATUS_PARTS_MAPPING.get(
+ m.group(0).replace('.', ''), m.group(0)),
+ name)
+ # Move prefixed status parts to the end for sorting
+ name = self.PREFIX_REGEXP.sub(self._rewrite_street_parts, name)
+ # TODO: move "малая", "большая" after name but before status
return name
def first_letter_equal(self, a, b):
diff --git a/ocitysmap/i18n_test.py b/ocitysmap/i18n_test.py
new file mode 100644
index 0000000..22db1e9
--- /dev/null
+++ b/ocitysmap/i18n_test.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8; mode: Python -*-
+import unittest
+import i18n
+
+class i18n_ru_generic_test(unittest.TestCase):
+ def setUp(self):
+ self.r = i18n.i18n_ru_generic('ru', '')
+
+ def test_readable_street(self):
+ conversions = [
+ (u"улица Ленина", u"Ленина, улица"),
+ (u"Улица Ленина", u"Ленина, улица"),
+ (u"Зеленая улица", u"Зеленая улица"),
+ (u"1-ый пер. Дзержинского", u"Дзержинского, переулок 1-ый"),
+ (u"1-ый переулок Дзержинского", u"Дзержинского, переулок 1-ый"),
+ (u"Красный 5-й пр-д", u"Красный 5-й проезд"),
+ (u"Красный 5-ый пр-д.", u"Красный 5-ый проезд"),
+ (u"1-й Барьерный переулок", u"Барьерный переулок, 1-й"),
+ (u"переулок К.Цеткин", u"К.Цеткин, переулок"),
+ (u" переулок К.Цеткин ", u"К.Цеткин, переулок"),
+ (u" переулок К.Цеткин ", u"К.Цеткин, переулок"),
+ (u"2-й Лётный переулок", u"Лётный переулок, 2-й"),
+ (u"2-й Малаховский проезд", u"Малаховский проезд, 2-й"),
+ (u"2-й Малаховский пр-д", u"Малаховский проезд, 2-й"),
+ (u"Житный переулок", u"Житный переулок"),
+ (u"10-я Текстильная улица", u"Текстильная улица, 10-я"),
+ (u"11-я линия В.О.", u"В.О., линия 11-я"),
+
+ # Not yet implemented:
+ #(u'Малая Пушкарская улица', u'Пушкарская малая, улица'),
+
+ # special case - no name, only prefix
+ (u"10-я аллея", u"10-я аллея"),
+ (u"123-я улица", u"123-я улица"),
+ ]
+ for fr, to in conversions:
+ self.assertEqual(to, self.r.user_readable_street(fr))
+
+if __name__ == '__main__':
+ unittest.main()
--
1.7.6.msysgit.0
- [Maposmatic-dev] [PATCH] Russian street name normal izer: i18n_ru_generic.user_readable_street , using table of status parts from streetmangler proje ct,
Konstantin Mochalov <=