Рекурсивное регулярное выражение с искаженным текстом, окружающим? Получение "ArrayArray"

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

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

Код, который я использую сейчас, возвращает 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 ответа

Решение
<?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;( а также )} ну или что еще ты хочешь.

Ваше регулярное выражение полностью введено в заблуждение.

Первый: [^...] является дополненным классом символов. Дополненный класс символов - это атом, и все ... is - это набор символов, которые не должны быть разрешены на этом этапе. То есть, [^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( будет трактоваться буквально, а не как метасимвол открытия группы.

Другие вопросы по тегам