Я хочу зафиксировать только первое совпадение

#regex #perl

#регулярное выражение #perl

Вопрос:

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

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

 ((d [A-z]?(s d/d)?|lots d [A-z]?|apts d [A-z]?)s [A-z] s [A-z] (s (avenue|street|road|drive))?)?
  

Строка:

Почтовый ЯЩИК МЕЙН-СТРИТ, 27, 85 МАЯ, РУЧКА

Функция Perl:

 sub hashaddress($)
{
    my $string = shift;

    if ($string =~ /s?((d [A-z]?(s d/d)?|lots d [A-z]?)s [A-z] s [A-z] (s (avenue|street|road|drive))?)?/gi)
    {
        $string =~ /s?((d [A-z]?(s d/d)?|lots d [A-z]?)s [A-z] s [A-z] (s (avenue|street|road|drive))?)?/gi;
        $string = $1;
    }

    return $string;
}
  

Функция perl возвращает «85 MAY PEN», когда мне нужно «27 MAIN STREET», что является первым совпадением.

Комментарии:

1. измените /gi на /i

2. /g В скалярном контексте продолжает поиск в строке с позиции предыдущего совпадения при каждом следующем вызове. Так что это while (/.../g) позволяет вам перебирать совпадения в строке по одному за раз. Но обычно вы не хотите этого в if условии (которое накладывает скалярный контекст). Я не понимаю, как это влияет на ваш результат здесь (это не работает таким образом при вызовах функций), но это /g может только навредить,

3. » Я не понимаю, как это влияет на ваш результат здесь » — подождите, я вижу это: ваше регулярное выражение выполняется в if условии, а затем снова внутри тела! Таким образом, выполнение внутри тела продолжается с того места, где остановилось предыдущее (в самом условии), и, таким образом, совпадает со следующим временем в строке.

Ответ №1:

Я не думаю, что вам нужен класс [A-z].
Немного сократив регулярное выражение, вы могли бы разрешить его следующим образом:

 sub hashaddress
{
    my ($string) = @_;

    if ( $string =~ /(?i)((d [a-z]?(s d/d)?|lots d [a-z]?)s [a-z] s [a-z] (s (avenue|street|road|drive))?)/ ) {  
        return $1;
    }
    return $string;
}
  

Информация о регулярном выражении:

  (?i)                          # Case insensitive
 (                             # (1 start)
      (                             # (2 start)
           d  [a-z]? 
           ( s  d / d )?              # (3)
        |  lot s  d  [a-z]? 
      )                             # (2 end)
      s  [a-z]  s  [a-z]  
      (                             # (4 start)
           s  
           (                             # (5 start)
                avenue 
             |  street
             |  road
             |  drive 
           )                             # (5 end)
      )?                            # (4 end)
 )                             # (1 end)