разбирать строку с потенциально 2 вхождениями одной и той же строки - PullRequest
3 голосов
/ 27 октября 2011

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

Вот пример ввода:

123 SUNNYSIDE AVENUE BROOKLYN
59 MAIDEN LANE MANHATTAN
59 MAIDEN LANE MANHATTAN 10038
39-076 46 STREET SUNNYSIDE
39-076 46 STREET SUNNYSIDE 11104
59 MAIDEN LANE MANHATTAN NY USA

В идеале группы регулярных выражений, возвращаемые для них, должны выглядеть следующим образом:

(123 )(SUNNYSIDE)( AVENUE )(BROOKLYN)
(59 MAIDEN LANE )(null)(null)(MANHATTAN)
(59 MAIDEN LANE )(null)(null)(MANHATTAN)
(39-076 46 STREET )(null)(null)(SUNNYSIDE)
(39-076 46 STREET )(null)(null)(SUNNYSIDE)
(59 MAIDEN LANE )(null)(null)(MANHATTAN)

Для городов у меня есть список (для этого примера не приведен) в такой группе регулярных выражений, например:

(MANHATTAN|BROOKLYN|SUNNYSIDE)

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

(.*?)(?:\W*)(MANHATTAN|BROOKLYN|SUNNYSIDE)(?:.*)

Но, конечно, это выдает:

(123)(SUNNYSIDE)

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

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

Ответы [ 3 ]

3 голосов
/ 27 октября 2011

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

^(.*?)\s+(MANHATTAN|BROOKLYN|SUNNYSIDE)\s*(\d*)$
1 голос
/ 27 октября 2011

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

"123 SUNNYSIDE AVENUE", "BROOKLYN"
"59 MAIDEN LANE", "MANHATTAN"
"59 MAIDEN LANE", "MANHATTAN"
"39-076 46 STREET", "SUNNYSIDE"
"39-076 46 STREET", "SUNNYSIDE"
"59 MAIDEN LANE", "MANHATTAN"

... или:

"123", "SUNNYSIDE", "AVENUE", "BROOKLYN"
"59", "MAIDEN", "LANE", "MANHATTAN"
"59", "MAIDEN", "LANE", "MANHATTAN"
"39-076", "46", "STREET", "SUNNYSIDE"
"39-076", "46", "STREET", "SUNNYSIDE"
"59", "MAIDEN", "LANE", "MANHATTAN"

В любом случае, я бы начал с сопоставления его с этим регулярным выражением:

^(\S+(?:\s+\S+)*)\s+(MANHATTAN|BROOKLYN|SUNNYSIDE)

Первая группа жадная, поэтому она будет первоначально потреблять все, кроме последнего слова адресной строки.Если последнее слово не является названием города (то есть оно не соответствует группе (MANHATTAN|BROOKLYN|SUNNYSIDE)), первая группа «сдает» по одному слову за раз, пока вторая группа не выполнит сопоставление .

Предполагая, что строка на самом деле содержит название города и имя включено в подвыражение второй группы, оно будет записано в группе # 2.Группа № 1 будет содержать полный адрес улицы;если вы хотите разбить его, как показано выше, вы можете разбить его на пробелы.

РЕДАКТИРОВАТЬ: Вот пример кода для демонстрации.Обратите особое внимание на использование find() вместо matches().Поведение Java matches() метода удивляет многих, и пришло в голову, что это может быть частью проблемы здесь.Вкратце, find() - это то, почему я должен был добавить ^ начало регулярного выражения, и почему я не должен был добавить .* в конец.;)

String[] ss = {
    "123 SUNNYSIDE AVENUE BROOKLYN",
    "59 MAIDEN LANE MANHATTAN",
    "59 MAIDEN LANE MANHATTAN 10038",
    "39-076 46 STREET SUNNYSIDE",
    "39-076 46 STREET SUNNYSIDE 11104",
    "59 MAIDEN LANE MANHATTAN NY USA"
};

Pattern p = Pattern.compile("^(\\S+(?:\\s+\\S+)*)\\s+(MANHATTAN|BROOKLYN|SUNNYSIDE)");
Matcher m = p.matcher("");

for (String s : ss)
{
  if (m.reset(s).find())
  {
    System.out.printf("%naddr: '%s'%ncity: '%s'%n", m.group(1), m.group(2));
  }
}

вывод:

addr: '123 SUNNYSIDE AVENUE'
city: 'BROOKLYN'

addr: '59 MAIDEN LANE'
city: 'MANHATTAN'

addr: '59 MAIDEN LANE'
city: 'MANHATTAN'

addr: '39-076 46 STREET'
city: 'SUNNYSIDE'

addr: '39-076 46 STREET'
city: 'SUNNYSIDE'

addr: '59 MAIDEN LANE'
city: 'MANHATTAN'
0 голосов
/ 27 октября 2011

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

^([\w -]*?)(MANHATTAN|BROOKLYN|SUNNYSIDE)(?:[ 0-9-]*)$

Разбитое, это выражение говорит:

^                                # Assert at beginning
(                                # Capture the following
   [\w -]                        #    Match letters, numbers, [space]'s and hyphens
   *?                            #    ...any number of times, but be reluctant
)                                # <end capture>
(MANHATTAN|BROOKLYN|SUNNYSIDE)   # Capture one of these three strings
(?:                              # Match but do not group the following
   [ 0-9-]*                      #    [space]'s, numbers, and hyphens
)                                # <end match>
$                                # Assert end of line

Это охватывает следующие группы:

(123 SUNNYSIDE AVENUE )     (BROOKLYN)
(59 MAIDEN LANE )           (MANHATTAN)
(59 MAIDEN LANE )           (MANHATTAN)
(39-076 46 STREET )         (SUNNYSIDE)
(39-076 46 STREET )         (SUNNYSIDE)

Если вы действительно хотите идентифицировать названия и типы улиц (например, SUNNYSIDE и AVENUE как отдельные группы), , но только если они совпадают с названиями городов , для этого потребуется более сложный выражение.

EDIT: Ваше выражение, когда оно сломлено, говорит:

(.*?)                            # Match any character except newline, any number of times, but be reluctant
(?:\W*)                          # Match but do not group any non-word character, any number of times
(MANHATTAN|BROOKLYN|SUNNYSIDE)   # Match one of these three strings
(?:.*)                           # Match but do not group any number of characters except newline

Ваше выражение, как написано, будет соответствовать всему, что может, вплоть до пробела (не состоящего из символов), затем совпадать с пробелом, а затем пытаться сопоставить то, что следует за пробелом, с одним из названий городов. Если бы это сработало, то это соответствовало бы чему-либо еще на линии. Если это не сработало, оно вернулось бы назад и соответствовало ранее упомянутому пробелу, а затем любым символам до следующего несловесного символа. Затем он совпадет с пробелом и продолжит цикл, пока не найдет название города.

Конструкция (?:) вокруг \W* по сути не имеет смысла, так как \W* - это одно совпадение, повторяемое любое количество раз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...