Я пытаюсь использовать php для разбиения строки на компоненты массива с помощью "
или '
в качестве разделителя. Я просто хочу разбить на внешнюю строку. Вот четыре примера и желаемый результат для каждого:
$pattern = "?????"; $str = "the cat 'sat on' the mat"; $res = preg_split($pattern, $str); print_r($res); /*output: Array ( [0] => the cat [1] => 'sat on' [2] => the mat )*/ $str = "the cat \"sat on\" the mat"; $res = preg_split($pattern, $str); print_r($res); /*output: Array ( [0] => the cat [1] => "sat on" [2] => the mat )*/ $str = "the \"cat 'sat' on\" the mat"; $res = preg_split($pattern, $str); print_r($res); /*output: Array ( [0] => the [1] => "cat 'sat' on" [2] => the mat )*/ $str = "the 'cat \"sat\" on' the mat 'when \"it\" was' seventeen"; $res = preg_split($pattern, $str); print_r($res); /*output: Array ( [0] => the [1] => 'cat "sat" on' [2] => the mat [3] => 'when "it" was' [4] => seventeen )*/
так как вы можете видеть, что я хочу разделить только внешнюю цитату, и я хочу игнорировать любые цитаты внутри цитат.
ближайший, который я придумал для $pattern
– это
$pattern = "/((?P<quot>['\"])[^(?P=quot)]*?(?P=quot))/";
но, очевидно, это не работает.
Вы можете использовать preg_split
с опцией PREG_SPLIT_DELIM_CAPTURE
. Регулярные выражения не так элегантны, как обратный подход @Jan Turoň, потому что требуемая группа захвата испортила результаты.
$str = "the 'cat \"sat\" on' the mat the \"cat 'sat' on\" the mat"; $match = preg_split("/('[^']*'|\"[^\"]*\")/U", $str, null, PREG_SPLIT_DELIM_CAPTURE); print_r($match);
Для этого можно использовать только preg_match
:
$str = "the \"cat 'sat' on\" the mat"; $pattern = '/^([^\'"]*)(([\'"]).*\3)(.*)$/'; if (preg_match($pattern, $str, $matches)) { printf("[initial] => %s\n[quoted] => %s\n[end] => %s\n", $matches[1], $matches[2], $matches[4] ); }
Это печатает:
[initial] => the [quoted] => "cat 'sat' on" [end] => the mat
Вот объяснение регулярного выражения:
/^([^\'"]*)
=> поместить начальный бит до первой котировки (одиночной или двойной) в первой захваченной группе (([\'"]).*\3)
=> захватить в \ 2 текст, соответствующий исходной кавычки (одно или двойной) (которая фиксируется в \ 3) до закрывающей цитаты (которая должна быть одинаковой тип как открывающая цитата, следовательно, \ 3). Тот факт, что регулярное выражение является жадным по своей природе, помогает получить от первой цитаты до последней, независимо от того, сколько цитат внутри. (.*)$/
=> Захват до конца в \ 4 Еще одно решение, использующее preg_replace_callback
$result1 = array(); function parser($p) { global $result1; $result1[] = $p[0]; return "|"; // temporary delimiter } $str = "the 'cat \"sat\" on' the mat 'when \"it\" was' seventeen"; $str = preg_replace_callback("/(['\"]).*\\1/U", "parser", $str); $result2 = explode("|",$str); // using temporary delimiter
Теперь вы можете array_map
эти массивы с помощью array_map
$result = array(); function zipper($a,$b) { global $result; if($a) $result[] = $a; if($b) $result[] = $b; } array_map("zipper",$result2,$result1); print_r($result);
И результат
[0] => the [1] => 'cat "sat" on' [2] => the mat [3] => 'when "it" was' [4] => seventeen
Примечание. Мне было бы лучше создать класс, выполняющий этот подвиг, поэтому можно избежать глобальных переменных.
Вы можете использовать обратные ссылки и модификатор ungreedy в preg_match_all
$str = "the 'cat \"sat\" on' the mat 'when \"it\" was' seventeen"; preg_match_all("/(['\"])(.*)\\1/U", $str, $match); print_r($match[0]);
Теперь у вас есть свои внешние цитаты
[0] => 'cat "sat" on' [1] => 'when "it" was'
И вы можете найти остальную часть строки с помощью substr
и strpos
(вид решения Blackbox)
$a = $b = 0; $result = array(); foreach($match[0] as $part) { $b = strpos($str,$part); $result[] = substr($str,$a,$b-$a); $result[] = $part; $a = $b+strlen($part); } $result[] = substr($str,$a); print_r($result);
Вот результат
[0] => the [1] => 'cat "sat" on' [2] => the mat [3] => 'when "it" was' [4] => seventeen
Просто разделите пустой пустой заголовок / конечный элемент, если цитата находится в самом начале / конце строки.