Как сделать регулярное выражение не голодным с кавычками?
Как сделать так, чтобы он не был голодным preg_match_all('/"[\p{L}\p{Nd}а-яА-ЯёЁ -_\.\+]+"/ui', $outStr, $matches);
3 ответа
Вы имеете в виду не жадный, как найти самый короткий матч вместо самого длинного? *
, +
, а также ?
квантификаторы по умолчанию жадные и будут максимально соответствовать. Добавьте знак вопроса после них, чтобы сделать их не жадными.
preg_match_all('/"[\p{L}\p{Nd}а-яА-ЯёЁ -_\.\+]+?"/ui', $outStr, $matches);
Жадный матч:
"foo" and "bar"
^^^^^^^^^^^^^^^
Нежадное совпадение:
"foo" and "bar"
^^^^^
Смотрите: http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php
U (PCRE_UNGREEDY)
Этот модификатор инвертирует "жадность" квантификаторов, так что они не являются жадными по умолчанию, но становятся жадными, если за ними следует?. Это не совместимо с Perl. Его также можно установить с помощью настройки модификатора (?U) в шаблоне или с помощью вопросительного знака за квантификатором (например, *?).
Ты предложил
/"[\p{L}\p{Nd}а-яА-ЯёЁ -_\.\+]+"/ui
который я представляю эквивалентно:
/"[\pL\p{Nd}а-яА-ЯёЁ -_.+]+"/ui
Чтобы показать людям, что вы используете не ASCII, если это не очевидно, используйте \x{⋯}
ускользает от этого:
/"[\pL\p{Nd}\x{430}-\x{44F}\x{410}-\x{42F}\x{451}\x{401} -_.+]+"/ui
И использование именованных символов это:
/"[\pL\p{Nd}\N{CYRILLIC SMALL LETTER A}-\N{CYRILLIC SMALL LETTER YA}\N{CYRILLIC CAPITAL LETTER A}-\N{CYRILLIC CAPITAL LETTER YA}\N{CYRILLIC SMALL LETTER IO}\N{CYRILLIC CAPITAL LETTER IO} -_.+]+"/ui
Кстати, они производятся путем запуска их через сценарийuniquote, первое использование uniquote -x
и второе использование uniquote -v
,
И да, я знаю или, по крайней мере, считаю, что PHP пока не поддерживает именованные символы, но об этом легче говорить. Кроме того, это гарантирует, что они не путают двойников:
U+0410 ‹А› \N{CYRILLIC CAPITAL LETTER A}
U+0430 ‹а› \N{CYRILLIC SMALL LETTER A}
U+0401 ‹Ё› \N{CYRILLIC CAPITAL LETTER IO}
U+0451 ‹ё› \N{CYRILLIC SMALL LETTER IO}
за:
U+0041 ‹A› \N{LATIN CAPITAL LETTER A}
U+0061 ‹a› \N{LATIN SMALL LETTER A}
U+00CB ‹Ë› \N{LATIN CAPITAL LETTER E WITH DIAERESIS}
U+00EB ‹ë› \N{LATIN SMALL LETTER E WITH DIAERESIS}
И теперь я думаю об этом, это все буквы, поэтому я не могу понять, почему вы перечисляете список кириллицы. Это потому, что вам нужны не все буквы кириллицы, а только этот конкретный набор? В противном случае я бы просто сделал:
/"[\pL\p{Nd} -_.+]+"/ui
В какой момент мне интересно об этом /i
, Я не могу понять, какова его цель, поэтому просто написал бы:
/"[\pL\p{Nd} -_.+]+"/u
Как уже упоминалось, обмен максимально количественно +
для соответствующей минимальной версии, +?
, буду работать:
/"[\pL\p{Nd} -_.+]+?"/u
Тем не менее, я обеспокоен этим диапазоном [ -_]
, то есть, \p{SPACE}-\p{LOW LINE}
, Я считаю, что это очень специфический диапазон. Это означает, что любой из этих
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
Во-первых, вы снова включили заглавные буквы ASCII. Для другого вы пропустили некоторые символы и знаки препинания:
% unichars -g '\p{ASCII}' '[\pS\pP]' 'ord() < ord(" ") || ord() > ord("_")'
` U+0060 GC=Sk GRAVE ACCENT
{ U+007B GC=Ps LEFT CURLY BRACKET
| U+007C GC=Sm VERTICAL LINE
} U+007D GC=Pe RIGHT CURLY BRACKET
~ U+007E GC=Sm TILDE
(Это вывод из сценарияunichars, если вам интересно.)
Что кажется странно произвольным. Поэтому мне интересно, может быть, это не достаточно хорошо для вас:
/"[\pL\p{Nd}\s\pS\pP]+?"/u
Теперь, когда я думаю об этом, эти два могут вызвать другие проблемы:
U+0401 ‹Ё› \N{CYRILLIC CAPITAL LETTER IO}
U+0451 ‹ё› \N{CYRILLIC SMALL LETTER IO}
Это предполагает, что они находятся в форме NFC (образованной каноническим составом канонического разложения). Если бы была вероятность того, что вы имеете дело с данными, которые не были нормализованы в форме NFC, то вам пришлось бы учитывать
NFD("\N{CYRILLIC CAPITAL LETTER IO}") => "\N{CYRILLIC SMALL LETTER IE}\N{COMBINING DIAERESIS}"
NFD("\N{CYRILLIC SMALL LETTER IO}") => "\N{CYRILLIC CAPITAL LETTER IE}\N{COMBINING DIAERESIS}"
А теперь у вас нет писем!
% uniprops "COMBINING DIAERESIS"
U+0308 ‹◌̈› \N{COMBINING DIAERESIS}
\w \pM \p{Mn}
All Any Assigned InCombiningDiacriticalMarks Case_Ignorable CI Combining_Diacritical_Marks Dia Diacritic M Mn Gr_Ext Grapheme_Extend Graph GrExt ID_Continue IDC Inherited Zinh Mark Nonspacing_Mark Print Qaai Word XID_Continue XIDC
Так что, возможно, вы бы на самом деле хотели:
/"[\pL\pM\p{Nd}\s\pS\pP]+?"/u
Если вы хотите ограничить вашу строку тем, что в ней будут только символы из латинского или кириллического алфавита (а не, скажем, греческого или катакана), вы бы добавили на этот счет дополнительные сведения:
/"(?:(?=[\p{Latin}\p{Cyrillic}])[\pL\pM\p{Nd}\s\pS\pP])+?"/u
Кроме того, что вам также нужно Common
чтобы получить цифры и различные обозначения и символы, и вам нужно Inherited
для объединения отметок после ваших писем. Это подводит нас к этому:
/"(?:(?=[\p{Latin}\p{Cyrillic}\p{Common}\p{Inherited}])[\pL\pM\p{Nd}\s\pS\pP])+?"/u
Теперь предлагается другой способ добиться минимального соответствия между двойными кавычками:
/"(?:(?!")(?=[\p{Latin}\p{Cyrillic}\p{Common}\p{Inherited}])[\pL\pM\p{Nd}\s\pS\pP])+"/u
Что становится все сложнее, чтобы не бежать /x
Режим:
/
" # literal double quote
(?:
### This group specifies a single char with
### three separate constraints:
# Constraint 1: next char must NOT be a double quote
(?!")
# Constraint 2: next char must be from one of these four scripts
(?=[\p{Latin}\p{Cyrillic}\p{Common}\p{Inherited}])
# Constraint 3: match one of either Letter, Mark, Decimal Number,
# whitespace, Symbol, or Punctuation:
[\pL\pM\p{Nd}\s\pS\pP]
) # end constraint group
+ # repeat entire group 1 or more times
" # and finally match another double-quote
/ux
Если бы это был Perl, я написал бы это с m{⋯}xu
m{
" # literal double quote
(?:
### This group specifies a single char with
### three separate constraints:
# Constraint 1: next char must NOT be a double quote
(?!")
# Constraint 2: next char must be from one of these four scripts
(?=[\p{Latin}\p{Cyrillic}\p{Common}\p{Inherited}])
# Constraint 3: match one of either Letter, Mark, Decimal Number,
# whitespace, Symbol, or Punctuation:
[\pL\pM\p{Nd}\s\pS\pP]
) # end constraint group
+ # repeat entire group 1 or more times
" # and finally match another double-quote
}ux
Но я не знаю, можете ли вы использовать парные, заключающие в скобки разделители, как это в PHP.
Надеюсь это поможет!