Как я могу исправить свое регулярное выражение, чтобы оно не слишком сильно совпадало с жадным квантификатором?[дубликат]

StackOverflow https://stackoverflow.com/questions/255815

Вопрос

У меня есть следующая строка:

"14:48 say;0ed673079715c343281355c2a1fde843;2;laka;hello ;)"

Я разбираю это с помощью простого регулярного выражения:

if($line =~ /(\d+:\d+)\ssay;(.*);(.*);(.*);(.*)/) {
    my($ts, $hash, $pid, $handle, $quote) = ($1, $2, $3, $4, $5);
}

Но тот ;в конце все портится, и я не знаю почему.Разве жадный оператор не должен обрабатывать "все"?

Это было полезно?

Решение

Жадный оператор пытается захватить как можно больше информации и при этом сопоставить строку.Что происходит, так это то, что первый (после "сказать") берет "0ed673079715c343281355c2a1fde843;2", второй берет "laka", третий находит "hello ", а четвертый соответствует скобке.

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

(\d+:\d+)\ssay;(.*?);(.*?);(.*?);(.*)

Другие советы

(\d+:\d+)\ssay;([^;]*);([^;]*);([^;]*);(.*)

должно работать лучше

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

Вместо этого я бы предложил что-то вроде этого:

$x="14:48 say;0ed673079715c343281355c2a1fde843;2;laka;hello ;)";

if (($ts,$rest) = $x =~ /(\d+:\d+)\s+(.*)/)
{
    my($command,$hash,$pid,$handle,$quote) = split /;/, $rest, 5;
    print join ",", map { "[$_]" } $ts,$command,$hash,$pid,$handle,$quote
}

Это приводит к:

[14:48],[say],[0ed673079715c343281355c2a1fde843],[2],[laka],[hello ;)]

Я думаю, что это просто немного более читабельно.Мало того, я думаю, что это также проще в отладке и обслуживании, потому что это ближе к тому, как вы бы это сделали, если бы человек попытался проделать то же самое с ручкой и бумагой.Разбейте строку на фрагменты, которые затем вам будет проще разобрать - пусть компьютер сделает именно то, что сделали бы вы.Когда придет время вносить изменения, я думаю, что с этим все будет лучше.ИММВ.

Попробуйте сделать первые 3 (.*) не жадный (.*?)

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

(\d+:\d+)\ssay;([a-f0-9]+);(\d+);(\w+);([^;\r\n]+)

Вы могли бы сделать * нежадным, добавив вопросительный знак:

$line =~ /(\d+:\d+)\ssay;(.*?);(.*?);(.*?);(.*)/

или вы можете сопоставить все, кроме точки с запятой, в каждой части, кроме последней:

$line =~ /(\d+:\d+)\ssay;([^;]*);([^;]*);([^;]*);(.*)/
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top