как сделать его не голодным - preg_match_all('/"[\p{L}\p{Nd}а-яА-ЯёЁ -_\.\+]+"/ui', $outStr, $matches);
Как сделать regexp не голодным с кавычками?
Ответ 1
Вы имеете в виду не жадные, как в поиске кратчайшего матча, а не самого длинного? Коэффициенты *
, +
и ?
являются жадными по умолчанию и будут соответствовать как можно больше. Добавьте знак вопроса после них, чтобы сделать их неживыми.
preg_match_all('/"[\p{L}\p{Nd}а-яА-ЯёЁ -_\.\+]+?"/ui', $outStr, $matches);
Жадный матч:
"foo" and "bar"
^^^^^^^^^^^^^^^
Нежелательное соответствие:
"foo" and "bar"
^^^^^
Ответ 2
Смотрите: http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php
U (PCRE_UNGREEDY)
Этот модификатор инвертирует "жадность" кванторов, поэтому что они не жадны по умолчанию, но становитесь жадными, если следовать?. Это не совместим с Perl. Оно может также устанавливаются установкой (? U) модификатора в рамках шаблона или вопросом пометить за квантификатором (например. *?).
Ответ 3
ou предложил
/"[\p{L}\p{Nd}а-яА-ЯёЁ -_\.\+]+"/ui
который я отправляю, эквивалентен:
/"[\pL\p{Nd}а-яА-ЯёЁ -_.+]+"/ui
Чтобы показать людям, которые не используются ASCII, если это не очевидно,
используя \x{⋯}
escape-последовательности, которые:
/"[\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
BTW, они создаются путем запуска их через uniquote script, первый использует 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:;<=>[email protected][\]^_
С одной стороны, вы снова включили буквы 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 script, если вам любопытно.)
Это кажется странно произвольным. Поэтому мне интересно, может ли это быть недостаточно для вас:
/"[\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.
Надеюсь, это поможет!