Рекурсивное регулярное выражение с искаженным текстом, окружающим?Получение "ArrayArray" - PullRequest
0 голосов
/ 30 декабря 2011

Я задал похожий вопрос, но он был закрыт из-за того, что он слишком широкий.По сути, у меня есть куча таких вопросов.Я надеюсь, что просто спросить одного будет легче.Я пробовал несколько разных способов решить эту проблему, но ни один из них на самом деле не работает.

У меня есть текстовый файл с большим количеством данных.Единственные данные, которые меня интересуют, лежат между двумя скобками "(" ")".Мне интересно, как получить каждый экземпляр информации, который находится в скобках, в массив.

Код, который я сейчас использую, возвращает ArrayArray:

function get_between($startString, $endString, $myFile){
  preg_match_all('/\$startString([^$endString]+)\}/', $myFile, $matches);
  return $matches;
}
$myFile = file_get_contents('explode.txt');
$list = get_between("&nbsp(", ")", $myFile);
foreach($list as $list){
  echo $list;
}

Ответы [ 2 ]

2 голосов
/ 30 декабря 2011

Ваше регулярное выражение введено в заблуждение.

Первое: [^...] - это дополненный класс символов.Дополненный класс символов - это атом, и все, что является ..., является набором символов, которые на данном этапе должны быть разрешены , а не .То есть, [^ab] разрешит все, кроме a и b.

Второе: вы, кажется, хотите иметь возможность захватывать между паренами.Но парен (открытый или закрытый) - это специальный символ в регулярном выражении.Таким образом, в вашем примере, если $startString равно &nbsp(, пара будет интерпретироваться как метасимвол регулярного выражения.

Третье: к сожалению, это не может быть решено с помощью регулярных выражений, но вложенные $startString и $endString не может быть сопоставлено (ну, они могут быть с perl, но perl это perl).

Самое близкое, что вы можете получить к тому, что вы действительно хотите, это переписать свое регулярное выражение для использования с preg_match_all следующим образом:

$start = preg_quote($startString, '/');
$end = preg_quote($endString, '/');
$re = '/\Q' . $start . '\E'       # literal $start
    . '('                         # capture...
    . '(?:(?!\Q' . $end . '\E).)' # any character, as long as $end is not found at this position,
    . '+)'                        # one or more times
    . '\Q' . $end . '\E/';        # literal $end

, а затем используйте это в качестве первого аргумента для preg_match_all.

Модификаторы регулярных выражений \Q и \E говорят, что все, что находится между первым и вторым, должно рассматриваться как литералы -следовательно, слово «ребенок» в &nbsp( будет трактоваться буквально, а не как метасимвол открытия группы.

1 голос
/ 30 декабря 2011
<?php
function get_between($startString, $endString, $myFile){
  //Escape start and end strings.
  $startStringSafe = preg_quote($startString, '/');
  $endStringSafe = preg_quote($endString, '/');
  //non-greedy match any character between start and end strings. 
  //s modifier should make it also match newlines.
  preg_match_all("/$startStringSafe(.*?)$endStringSafe/s", $myFile, $matches);
  return $matches;
}
$myFile = 'fkdhkvdf(mat(((ch1)vdsf b(match2) dhdughfdgs (match3)';
$list = get_between("(", ")", $myFile);
foreach($list[1] as $list){
  echo $list."\n";
}

Я сделал это, и, кажется, работает.(Очевидно, вам нужно заменить мою строку назначения $ myFile на вашу инструкцию file_get_contents.) Несколько вещей:

A: Замена переменной не будет происходить с одинарными кавычками.Таким образом, ваше регулярное выражение preg_replace_all не будет работать в результате.Поскольку он буквально добавляет $ startString к вашему выражению вместо (. (Я также удалил проверку для} в конце совпавшей строки. Добавьте его обратно, если вам нужно, с помощью \\} непосредственно перед конечным разделителем.)

B: $ list будет массивом массивов. Я считаю, что по умолчанию индекс ноль будет содержать все полные совпадения. Индекс один будет содержать первое совпадение подшаблона.

C: Это работает только так долгопоскольку $ endString никогда не будет найден внутри подшаблона, который вы пытаетесь сопоставить. Скажем, если вы ожидаете, что (matc (fF)) даст вам matc (fF), этого не будет. Он даст вам совпадение (fFВам понадобится более мощный синтаксический анализатор, если вы хотите получить прежний результат в этом случае.

Редактировать: функция get_between здесь должна работать также с &nbsp;( и )}, или с чем угодно ещехотел бы.

...