Регулярное выражение для разделения немецкого адреса на части

Добрый вечер,

Я пытаюсь разбить немецкую адресную строку на части с помощью Java. Кто-нибудь знает регулярное выражение или библиотеку для этого? Чтобы разделить его следующим образом:

Name der Straße 25a 88489 Teststadt
to
Name der Straße|25a|88489|Teststadt

or

Teststr. 3 88489 Beispielort (Großer Kreis)
to
Teststr.|3|88489|Beispielort (Großer Kreis)

Было бы идеально, если бы система / регулярное выражение все равно работало бы, если такие части, как почтовый индекс или город, отсутствуют.

Есть ли какое-нибудь регулярное выражение или библиотека, с помощью которой я мог бы заархивировать это?

РЕДАКТИРОВАТЬ: Правило для немецких адресов:
Улица: символы, числа и пробелы
Номер дома: номер и любые символы (или пробел) до ряда цифр (почтовый индекс) (по крайней мере, в эти примеры)
Zip: 5 цифр
Место или город: остальные также могут быть с пробелами, запятыми или фигурными скобками


person Christian Kolb    schedule 25.03.2012    source источник
comment
Какое правило для тех, кто не знаком с немецкими адресами? Это что-то с пробелами, но не с числами, что-то с числами, но без пробелов, чисел и без пробелов, без чисел и без пробелов?   -  person Oliver Charlesworth    schedule 26.03.2012
comment
для этого вам не нужно регулярное выражение. Просто разделите строку, используя разделитель пробелов, а затем присоединитесь к ней, используя разделитель |, но комментарий Оли выше также уместен, поскольку я предполагаю, что немецкие адреса разделены пробелами   -  person Robbie    schedule 26.03.2012
comment
@OliCharlesworth: отредактировал сообщение   -  person Christian Kolb    schedule 26.03.2012
comment
@Robbie: Я не могу просто разделить их пробелами, потому что название улицы и город / место тоже могут содержать пробелы.   -  person Christian Kolb    schedule 26.03.2012
comment
Не думаю, что это так просто. Есть много названий улиц с пробелами. Кроме того, некоторые люди пишут «25 а» вместо «25 а». Я бы обычно писал свой адрес с ',', чтобы разделить части. Получаете ли вы адреса из другой системы в определенном формате?   -  person bert    schedule 26.03.2012
comment
@Christian: Хорошо. Тогда ответ на ваш вопрос: да, это можно сделать с помощью регулярного выражения.   -  person Oliver Charlesworth    schedule 26.03.2012
comment
@OliCharlesworth: Я так и думал, я надеялся, что есть кто-то, кто это уже сделал, и у любого из вас будет ссылка на него;)   -  person Christian Kolb    schedule 26.03.2012
comment
@bert Да, я получил его из другой системы, но адреса ненормализованы, и иногда отсутствуют какие-либо части. Вот что делает его таким сложным. Но я подумал, что не могу первым столкнуться с этой проблемой, и для этого нужна библиотека или регулярное выражение.   -  person Christian Kolb    schedule 26.03.2012
comment
Обычное правило (с которым я знаком) - разделять каждую часть новой строкой или запятыми. Я никогда не видел вышеуказанную форму без них… но с этим не должно быть слишком сложно; однако он не масштабируется: в адресе есть другие необязательные части, которые могут сделать это неоднозначным.   -  person Konrad Rudolph    schedule 26.03.2012
comment
Некоторые люди пишут D 72116 вместо 72116 специально для устранения неоднозначности из австрийских и швейцарских местоположений.   -  person Ingo    schedule 26.03.2012


Ответы (6)


Я столкнулся с аналогичной проблемой и немного изменил решения, представленные здесь, и пришел к этому решению, которое также работает, но (imo) немного проще понять и расширить:

/^([a-zäöüß\s\d.,-]+?)\s*([\d\s]+(?:\s?[-|+/]\s?\d+)?\s*[a-z]?)?\s*(\d{5})\s*(.+)?$/i

Вот несколько примеров совпадений.

Он также может обрабатывать отсутствующие номера улиц и легко расширяется путем добавления специальных символов в классы символов.

[a-zäöüß\s\d,.-]+?                         # Street name (lazy)
[\d\s]+(?:\s?[-|+/]\s?\d+)?\s*[a-z]?)?     # Street number (optional)

После этого должен быть почтовый индекс, который является единственной частью, которая абсолютно необходима, потому что это единственная постоянная часть. Все, что находится после почтового индекса, считается названием города.

person F.P    schedule 30.03.2012

Я бы начал с обратной стороны, поскольку, насколько мне известно, название города не может содержать чисел (но может содержать пробелы (первый пример, который я нашел: «Weil der Stadt"). Затем пятизначное число перед ним должно быть почтовым индексом.

Номер (возможно, за которым следует одна буква) перед ним - это номер улицы. Обратите внимание, что это также может быть диапазон. Все, что перед этим, - это название улицы.

В любом случае, поехали:

^((?:\p{L}| |\d|\.|-)+?) (\d+(?: ?- ?\d+)? *[a-zA-Z]?) (\d{5}) ((?:\p{L}| |-)+)(?: *\(([^\)]+)\))?$

Это правильно анализирует даже загадочные адреса, такие как «Straße des 17. Juni 23-25 ​​a 12345 Berlin-Mitte».

Обратите внимание, что это не работает с расширениями адресов (такими как «Gartenhaus» или «c / o…»). Я понятия не имею, как с этим справиться. Я очень сомневаюсь, что существует жизнеспособное регулярное выражение, чтобы выразить все это.

Как видите, это довольно сложное регулярное выражение с множеством групп захвата. Если я бы использовал такое выражение в коде, я бы использовал именованные захваты (Java 7 поддерживает их) и разбил бы выражение на более мелкие кусочки, используя флаг x. К сожалению, Java не поддерживает это. Это дерьмо, потому что это делает сложные регулярные выражения непригодными для использования.

Тем не менее, вот несколько более разборчивое регулярное выражение:

^
(?<street>(?:\p{L}|\ |\d|\.|-)+?)\ 
(?<number>\d+(?:\ ?-\ ?\d+)?\ *[a-zA-Z]?)\ 
(?<zip>\d{5})\ 
(?<city>(?:\p{L}|\ |-)+)
(?:\ *\((?<suffix>[^\)]+)\))?
$

В Java 7 самое близкое, что мы можем достичь, это (не проверено; может содержать опечатки):

String pattern =
    "^" +
    "(?<street>(?:\\p{L}| |\\d|\\.|-)+?) " +
    "(?<number>\\d+(?: ?- ?\\d+)? *[a-zA-Z]?) " +
    "(?<zip>\\d{5}) " +
    "(?<city>(?:\\p{L}| |-)+)" +
    "(?: *\\((?<suffix>[^\\)]+)\\))?" +
    "$";
person Konrad Rudolph    schedule 25.03.2012
comment
Работает как амулет для вашей уличной струны, но, к сожалению, не для этой уличной строки. Вы можете протестировать это с помощью примера кода radzio и вашего Regex (с экранированными частями) ^((?:\\p{L}| |\\d|\\.|-)+?) ((?:\\d+ ?- ?)\\d+ *[a-zA-Z]?) (\\d{5}) ((?:\\p{L}| |-)+)$ - person Christian Kolb; 26.03.2012
comment
@Christian Потому что я идиот. Повторите попытку, я неправильно указал диапазон номеров улиц и не сделал его необязательным. Теперь это работает на примерах адресов. - person Konrad Rudolph; 26.03.2012
comment
Найдена одна недостающая часть. Иногда в месте, определяющем область, есть фигурные скобки (и). Они не являются частью официального адреса, но они есть в таких данных. Можно ли добавить это в регулярное выражение? А если как? - person Christian Kolb; 26.03.2012
comment
@Christian Хм, а где именно скобки? Пожалуйста, отредактируйте вопрос с примером. - person Konrad Rudolph; 26.03.2012
comment
Можно ли сказать, что место вообще может состоять из любых символов, кроме цифр? Потому что я нашел следующий адрес: Schwabacher Str. 22 48516 Эшборн, Таунус. Адрес с запятой,. Это не будет работать с регулярным выражением. - person Christian Kolb; 26.03.2012
comment
Извините, что так много рассказываю, но это тоже, похоже, не работает. или / на Улице, когда между ними нет места, как следующий Hölzlestr.44 / 1. И можно ли сделать дом необязательным? Иногда на улице всего один дом, и тогда дома не ставят. Еще раз извиняюсь за то, что просил о многом, и еще раз спасибо за вашу помощь. - person Christian Kolb; 26.03.2012
comment
О боже. Но да, это должно сработать. Просто адаптируйте часть регулярного выражения «город» и либо добавьте запятую к альтернативам, либо замените все эти альтернативы символом подстановки - на самом деле, город и достаточно, вероятно, можно было бы объединить, просто сказав (?<city>.+) вместо них. Мое первоначальное выражение довольно осторожно в том, что оно позволяет, а что не позволяет. - person Konrad Rudolph; 26.03.2012
comment
@Christian Я думаю, что теперь вы достигли предела возможностей регулярных выражений, это по своей сути неоднозначно. Что означает «Straße 1 00000 Stadt»? Улица Straße 1 с одним домом? Или дома нет. 1 на улице Straße? Я не понимаю, как различать без машинного обучения. Конечно, не с помощью регулярных выражений. Но пробел после названия улицы можно сделать необязательным. Просто поставьте вопросительный знак в пробел после части «улица» регулярного выражения. - person Konrad Rudolph; 26.03.2012
comment
Да, ты прав. Регулярное выражение - это не мозг :) Но должна быть возможна еще одна вещь: использование / в доме нет. Как Hölzlestr.44 / 1. Что мне нужно изменить в регулярном выражении, чтобы оно работало с ним? - person Christian Kolb; 26.03.2012
comment
@Christian Хм. Номера домов уже допускают диапазоны. Просто замените часть `? -?` (Обратите внимание на пробелы) на `? [- |]?`… Это должно сработать. - person Konrad Rudolph; 26.03.2012

Вот мое предложение, которое можно дополнительно доработать, например. чтобы допустить недостающие части.

Шаблон регулярного выражения:

^([^0-9]+) ([0-9]+.*?) ([0-9]{5}) (.*)$
  • Группа 1: Улица
  • Группа 2: Дом №
  • Группа 3: ZIP
  • Группа 4: Город
person Michael Schmeißer    schedule 25.03.2012
comment
Это регулярное выражение не работает, поскольку названия улиц могут содержать числа. Например (но не исключительно), улицы могут быть пронумерованы перед присвоением им названий, чтобы в итоге получилось «Straße 42». Другой пример - «Straße des 17. Juni». - person Konrad Rudolph; 26.03.2012
comment
OP не упоминал номера в названиях улиц. Может и не надо за тех держать? - person keyser; 26.03.2012
comment
@KonradRudolph Ты прав. Это возможность, которая полностью выскользнула из моей головы. Есть ли система, с помощью которой вы можете определить, как строится немецкий адрес? - person Christian Kolb; 26.03.2012
comment
@KonradRudolph Вопрос четко определяет часть улицы как Street: символы и пробелы до числа, поэтому мое регулярное выражение не нарушено. Я просто ответил на вопрос. Если, как подтвердил Кристиан, вопрос неверен с учетом этой части, может потребоваться другое решение, но я бы попросил Кристиана изменить вопрос. - person Michael Schmeißer; 26.03.2012
comment
@Michael Да, в вопросе неверно указан ввод. Регулярное выражение все еще не работает при реалистичном вводе. Это не твоя вина, но все же верно. - person Konrad Rudolph; 26.03.2012
comment
@KonradRudolph У нас другое понимание сломанного. Для меня то, что соответствует спецификации (вопрос в данном случае), не нарушено. - person Michael Schmeißer; 26.03.2012
comment
@Michael Действительно так кажется. Если спецификации явно нарушены, значит, код соответствует спецификациям. В конце концов, мы программируем для реального мира, а не для какой-то идеалистической модели, описанной на бумаге. - person Konrad Rudolph; 26.03.2012
comment
@KonradRudolph Многие разработчики программного обеспечения заключают контракты (на основе спецификации) с клиентами, которые хотят получить программное обеспечение. Часто бывает, что заказчик не сказал того, чего он на самом деле хотел в своем реальном мире. Однако программист не может произвольно угадывать, что заказчик может захотеть получить, потому что, если он угадает неправильно, это нанесет компании значительные убытки. Так что я бы не стал делать предположения относительно моей спецификации. Максимум, что я хотел бы сделать, это попросить разъяснений, если это кажется действительно странным. - person Michael Schmeißer; 26.03.2012

public static void main(String[] args) {
    String data = "Name der Strase 25a 88489 Teststadt";
    String regexp = "([ a-zA-z]+) ([\\w]+) (\\d+) ([a-zA-Z]+)";

    Pattern pattern = Pattern.compile(regexp);
    Matcher matcher = pattern.matcher(data);
    boolean matchFound = matcher.find();

    if (matchFound) {
        // Get all groups for this match
        for (int i=0; i<=matcher.groupCount(); i++) {
            String groupStr = matcher.group(i);
            System.out.println(groupStr);
        }
    }System.out.println("nothing found");
                }

Я думаю, это не работает с немецкими умляутами, но вы можете исправить это самостоятельно. В любом случае это хороший стартап.

Я рекомендую посетить это отличный сайт о регулярных выражениях. Удачи!

person Radek Busz    schedule 25.03.2012
comment
Это не работает по той же причине, что и другое регулярное выражение, указанное выше. - person Konrad Rudolph; 26.03.2012
comment
Вы имеете в виду название улицы, на которой могут быть числа? Я предполагаю, что это не было четко указано в вопросе. - person Radek Busz; 26.03.2012
comment
Например. Происходит еще много безумных вещей. Немецкие адреса чертовски сложны. Подробности смотрите в моем ответе. - person Konrad Rudolph; 26.03.2012
comment
как насчет if String data = 88489 Teststadt Name der Strase 25a; как будет шаблон Regex? Спасибо - person Souheib Selmi; 06.02.2021

На первый взгляд кажется, что для этого подойдет простой пробел, однако, присмотревшись, я замечаю, что адрес всегда состоит из 4 частей, а в первой части могут быть пробелы.

Я бы сделал что-то вроде этого (псевдокод):

address[4] = empty
split[?] = address_string.split(" ")
address[3] = split[last]
address[2] = split[last - 1]
address[1] = split[last - 2]
address[0] = join split[first] through split[last - 3] with whitespace, trim trailing whitespace with trim()

Однако это будет обрабатывать только одну форму адреса. Если адреса записываются несколькими способами, это может быть намного сложнее.

person vgel    schedule 25.03.2012

попробуй это:

^[^\d]+[\d\w]+(\s)\d+(\s).*$

Он захватывает группы для каждого из пробелов, которые ограничивают 1 из 4 разделов адреса.

OR

это дает вам группы для каждой из частей адреса:

^([^\d]+)([\d\w]+)\s(\d+)\s(.*)$

Я не знаю java, поэтому не уверен, какой именно код использовать для замены захваченных групп.

person Robbie    schedule 25.03.2012