как соответствовать только один раз в регулярном выражении Perl - PullRequest
1 голос
/ 20 октября 2010
$line = " TEST: asdas :asd asdasad s";

if ($line =~ /(.*):(.*)/
{
  print "$1  = $2 "
}

Я ожидал TEST =asdas :asd asdasad s

но это не работает?в чем проблема

Ответы [ 5 ]

12 голосов
/ 20 октября 2010

Правильный путь будет:

/([^:]+):(.*)/

или

/(.+?):(.*)/

Таким образом, вы не соответствуете «чему-либо» слева, вы соответствуете «одному илибольше символов, отличных от двоеточия »в первом примере или« сопоставление кратчайшей возможной строки из любых символов, за которой следует двоеточие »во втором.Используйте split.

my ($left,$right) = split( /:/, $line, 2 );

,2 говорит: «Я хочу не более двух полей».

4 голосов
/ 21 октября 2010

Проблема, как говорят другие, в том, что вы сопоставляете все, кроме строки, заканчивающейся жадно (.*).Но что они не говорят вам, что когда механизм регулярных выражений сопоставляет все до конца строки, он должен вернуть , чтобы удовлетворить условию ':'.Поэтому после того, как он поглотит все символы, не являющиеся переводом строки, он начнет резервное копирование.Поскольку теперь происходит обратное, первое найденное двоеточие - это «:» прямо перед «asd».После сопоставления двоеточия вторая группа применяется ко всем символам, не являющимся символами перевода строки, которым она удовлетворяет.

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

([^:]+):(.*)

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

([^:]+):(.*\S)

Когда он добирается до конца ввода, он возвращается к тому месту без пробела, которое ему еще не соответствует.И когда он находит это, он прекращает захват.

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

([^:]+):((?:\S| \S)+)

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

В этом сообщении от Regex Guru есть немного больше об этом.

2 голосов
/ 20 октября 2010

Две проблемы:

  1. состояло в том, что вам нужна заключительная скобка, ), в конце вашего if оператора
  2. вы хотите non - жадное выражение, соответствующее количеству минимум перед первым двоеточием (:)

Попробуйте $line =~ m/(.*?):(.*)/ - обратите внимание на .*? - это означает, что соответствует минимум требуется .Обычно .* означает совпадение максимально возможное .

1 голос
/ 20 октября 2010
$line = " TEST: asdas :asd asdasad s";

if ($line =~ /(.*?):(.*)/)
{
    print "$1  = $2 "
}

Используйте вышеупомянутое.Здесь (. *?) Означает не жадное сопоставление.Так что он будет совпадать, пока не найдет первое ':'

1 голос
/ 20 октября 2010

Создание первого .* нежадного также будет работать:

if ($line =~ /(.*?):(.*)/) {
  print "$1  = $2 "
}
...