Как я могу извлечь группы непробельных символов из строки в Perl? - PullRequest
1 голос
/ 21 апреля 2010

Я пишу программу, которая должна получать значения из файла. В файле каждая строка указывает на сущность. У каждого объекта есть три значения. Например:

Значение1 Значение2 Значение3

У меня есть регулярные выражения, соответствующие им

m/(.*?) (.*?) (.*?)/m;

Но, похоже, третье значение никогда не совпадало! Единственный способ сопоставить третье значение - это добавить еще одно значение в файл и еще один «соответствующий квадрат» в выражении. Но это меня не удовлетворяет.

Ответы [ 4 ]

8 голосов
/ 21 апреля 2010

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

@s = split /\s+/ , $line;
7 голосов
/ 21 апреля 2010

Что происходит

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

 /.*? .*? .*?/

Значение .*? означает «соответствовать любому символу (кроме новой строки), ни разу, ни как можно меньше».

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

Другими словами, это тот факт, что после группы .*? у нас есть пробел, который соответствует тому, что вы хотите. В противном случае он просто перестанет совпадать с нулем символов.

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

Способы избежать этого

Как сказали другие ответы, возможные решения включают:

  • split (лучшая транскрипция предполагаемой семантики ИМО)
  • делает последний захват жадным (.* вместо .*?)
  • добавление чего-либо (всего, что соответствует) после последнего захвата. $ если строка заканчивается там
  • соответствие без пробелов (\S) вместо любых символов (.). Это будет работать либо с жадными (\S*), либо с несжатыми (\S*?) совпадениями.
5 голосов
/ 21 апреля 2010

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

Строка, которую вы хотите сопоставить, имеет:

  1. Некоторые без пробелов
  2. Некоторые пробелы
  3. повторить еще два раза

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

 my @values = /(\S+) (\S+) (\S+)/;

Поскольку вы использовали \S, части шаблона в перехвате не могут пройти через пробел, чтобы соответствовать больше, чем вы предполагали, как может .*.

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

 my @values = /(\S+)/g;

Вы также можете подумать об обратном. Вместо того, чтобы захватывать пустое пространство, вы можете выбросить пустое пространство с помощью split :

 my @values = split /\s+/;
5 голосов
/ 21 апреля 2010

Поставьте $ в конце regex, чтобы решить эту проблему:

m/(.*?) (.*?) (.*?)$/m;

В качестве альтернативы вы можете сделать последнюю часть greedy:

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