#php #regex
Вопрос:
Следующий пример:
$text = <<<END
some text
q 1
some next line
q 2 test
exptra line
END;
$text = trim($text);
if (preg_match_all("/nQs d .[^n]*n/isU", $text, $match)) {
print_r($match);
echo "OK";
} else {
echo "FAIL";
}
Выход:
Array
(
[0] => Array
(
[0] =>
q 1
some next line
[1] =>
q 2 test
)
)
OK
Пожалуйста, обратите внимание, что новая строка в примере для $text
состоит только из одной n
.
По какой-то причине .[^n]*
включает символ новой строки, даже если он указан как исключающий. Это происходит только в том случае, если новая строка является единственным символом, соответствующим этой части выражения ( n
идет сразу после 1), и звездочка ( *
), которая должна означать, что любое количество символов, включая none/необязательно, не воспроизводится здесь правильно.
Поскольку мне нужно сопоставить оба случая, что можно сделать в этом случае?
Ожидаемый результат, чтобы соответствовать обеим строкам, начинающимся со q N
следующей строки, но без нее:
Array
(
[0] => Array
(
[0] =>
q 1
[1] =>
q 2 test
)
)
Приведенный выше пример упрощен. Сопоставленная строка может содержать символы новой строки, но не в указанном месте. На самом деле я тестировал .
с другими символами, и это работает так же. Если для точки остается только один символ, который указан как исключающий — он все равно включает его:
$text = <<<END
some text
q 1e
some next line
q 2 test
exptra line
END;
$text = trim($text);
if (preg_match_all("/Qs d .[^e]*/iU", $text, $match)) {
print_r($match);
echo "OK";
} else {
echo "FAIL";
}
Выход:
Array
(
[0] => Array
(
[0] => q 1e
[1] => q 2
)
)
Комментарии:
1.
.
совпаденияn
, потому что у вас естьs
флаг.[^n]*
соответствует нулю или более не-LFS, поэтому это не ограничивает.
здесь. Что вы ожидаете здесь получить?2. Попробуй
preg_match_all('~^Qh d.*~im', $text, $matches)
. Смотрите демонстрацию регулярных выражений.3. Добавлен ожидаемый результат. Из
s
документации по модификаторамA negative class such as [^a] always matches a newline character
, поэтому на самом деле не должно иметь значения,s
установлен модификатор или нет для этого случая.n
указано как «исключить» символ и не должно быть включено, как во втором случае.4.
s
флаг изменяет поведение.
, а не[^a]
то , что вы перепутали с документами здесь.5. Я имею в виду, что
.[^a]
в соответствии с документацией символ новой строки все равно включается, независимо от того, есть лиs
место или нет.
Ответ №1:
Ваше /Qs d .[^e]*/iU
регулярное выражение содержит U
флаг (PCRE_UNGREEDY), который меняет местами жадность кванторов и равен /Qs ?d ?.[^e]*?/i
шаблону. /Qs ?d ?.[^e]*?/i
играм q
или Q
, кто либо еще, но как можно меньше пробелов, символов, тогда один или более, но при этом как можно меньше цифр, а затем любой символ (кроме разрыва строки char, если s
флаг опущен) и потом — посмотри — любое ноль или больше символов, чем другие e
как можно меньше (т. е. он не соответствует ни одному тексту, как это не обязательно).
Вы можете использовать
<?php
$text = <<<END
some text
q 1
some next line
q 2 test
exptra line
END;
if (preg_match_all('~^Qh d.*~im', $text, $match)) {
print_r($match);
echo "OK";
} else {
echo "FAIL";
}
Смотрите демонстрационную версию PHP. Выход:
Array
(
[0] => Array
(
[0] => q 1
[1] => q 2 test
)
)
OK
Детали узора:
^
— начало строки (из-заm
флага)Q
—Q
илиq
(из-заi
флага)h
— один или несколько горизонтальных пробеловd
— цифра.*
— любые нулевые или более символов, кроме символов разрыва строки (поскольку я не используюs
флаг), как можно больше (т. Е. Остальная часть строки).
Комментарии:
1. Извините, не могу принять ответ. Приведенный выше пример упрощен. Сопоставленная строка может содержать символы новой строки, но не в указанном месте. На самом деле я тестировал
.
с другими символами, и это работает так же. Если для точки остается только символ, указанный как исключающий, — он все равно включает его. См.добавленный пример.2. @Index Если вы объясните свои требования к шаблону на простом английском языке, было бы намного проще предоставить вам 100% рабочее решение. Ваши примеры не проясняют, чего вы на самом деле хотите достичь. Пожалуйста, ознакомьтесь с деталями моего шаблона и составьте набор требований, используя аналогичный стиль.
3. @Index Я добавлю объяснение, почему вы получаете эти совпадения, возможно, это даст вам подсказку.
Ответ №2:
Модификатор s
переключает поведение .
. Потому что вы включили его в .
соответствие n
с завещанием .
Небольшая демонстрация:
$patterns = [
'(.*)', '(.*)s', '([^\n]*)'
];
foreach ($patterns as $pattern) {
preg_match($pattern, "foonbar", $match);
echo $pattern, ': "', $match[0], ""n";
}
Выход:
(.*): "foo"
(.*)s: "foo
bar"
([^n]*): "foo"
Модификатор m
был бы более подходящим в вашем случае. Это изменяет поведение ^
и $
соответствует началу/концу строки (а не только строки).
$pattern = '(
^q # letter q or Q at line start (with modifier m)
\s # at least one whitespace
(?<number>\d ) # string of digits - named group "number"
(?<label>[^\n]*) # any character except "n" (without modifier s) - named group "label"
)xmi';
if (preg_match_all($pattern, $text, $match, PREG_SET_ORDER)) {
print_r($match);
}
Выход:
Array
(
[0] => Array
(
[0] => q 1
[number] => 1
[1] => 1
[label] =>
[2] =>
)
[1] => Array
(
[0] => q 2 test
[number] => 2
[1] => 2
[label] => test
[2] => test
)
)
Модификатор x
включает «расширенный синтаксис». Это позволяет форматировать и документировать шаблон.
Я предлагаю использовать именованные группы для получения результатов. Это делает код более читабельным и надежным. PREG_SET_ORDER
помещает данные для каждого совпадения в набор.