PHP: лучший способ извлечь текст в скобках?

83

Какой лучший / самый эффективный способ извлечь текст, заключенный в круглые скобки? Скажем, я хотел получить строку «текст» из строки «игнорировать все, кроме этого (текста)» наиболее эффективным способом.

Пока что лучшее, что я придумал, это следующее:

$fullString = "ignore everything except this (text)";
$start = strpos('(', $fullString);
$end = strlen($fullString) - strpos(')', $fullString);

$shortString = substr($fullString, $start, $end);

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

Wilco
источник
Вы можете найти s($fullString)->between("(", ")")полезные сведения, найденные в этой автономной библиотеке .
caw

Ответы:

144

Я бы просто сделал регулярное выражение и покончил с этим. если вы не делаете достаточно итераций, чтобы это стало огромной проблемой для производительности, просто кодировать проще (и понять, когда вы оглянетесь на это)

$text = 'ignore everything except this (text)';
preg_match('#\((.*?)\)#', $text, $match);
print $match[1];
Оуэн
источник
1
Нет, это не так:. соответствует только одному символу.
Эдвард З. Янг,
1
не обязательно, ? ленивый матч. без него строка вроде «игнорировать (все) кроме этого (текста)», совпадение будет «все», кроме этого (текст)
Оуэн,
1
Хорошо знать. Следует избегать всех этих квадратов. Например, / src = "([^"] *) "/ теперь заменено на /src="(.*?)"/: D
Димитрий
Хорошо, что можно «понять, оглянувшись на это». В противном случае у вас есть несколько комментариев по переполнению стека, чтобы прояснить это.
Mnebuerquo,
2
/ src = "([^"] *) "/ более эффективен, чем /src="(.*?)"/
Tanj
14

Так, собственно, код размещен не работает: substr()'sпараметры $ строка, $ начала и $ длина и strpos()'sпараметры $haystack, $needle. Немного изменено:

$ str = "игнорировать все, кроме этого (текста)";
$ начало = strpos ($ str, '(');
$ end = strpos ($ str, ')', $ start + 1);
$ length = $ end - $ начало;
$ result = substr ($ str, $ start + 1, $ length - 1);

Некоторые тонкости: я использовал $start + 1параметр смещения, чтобы помочь PHP при strpos()поиске по второй скобке; мы увеличиваем $startединицу и уменьшаем, $lengthчтобы исключить скобки из совпадения.

Кроме того, в этом коде нет проверки ошибок: вы захотите убедиться $startи $endне использовать === false перед выполнением substr.

Что касается использования по strpos/substrсравнению с регулярным выражением; с точки зрения производительности этот код превзойдет регулярное выражение. Хотя это немного многословнее. Я ем и дышу strpos/substr, поэтому я не особо возражаю против этого, но кто-то другой может предпочесть компактность регулярного выражения.

Эдвард З. Янг
источник
1
Обратите внимание, что если вы измените этот код для использования strrpos (начинается с конца строки) в конце $, тогда он будет правильно обрабатывать случаи, когда есть скобки внутри ... например (ну, это (очень) хорошо).
ftrotter
9

Используйте регулярное выражение:

if( preg_match( '!\(([^\)]+)\)!', $text, $match ) )
    $text = $match[1];
Роб
источник
3

Это образец кода для извлечения всего текста между '[' и ']' и сохранения его в двух отдельных массивах (т.е. текст внутри круглых скобок в одном массиве и текст вне скобок в другом массиве)

   function extract_text($string)
   {
    $text_outside=array();
    $text_inside=array();
    $t="";
    for($i=0;$i<strlen($string);$i++)
    {
        if($string[$i]=='[')
        {
            $text_outside[]=$t;
            $t="";
            $t1="";
            $i++;
            while($string[$i]!=']')
            {
                $t1.=$string[$i];
                $i++;
            }
            $text_inside[] = $t1;

        }
        else {
            if($string[$i]!=']')
            $t.=$string[$i];
            else {
                continue;
            }

        }
    }
    if($t!="")
    $text_outside[]=$t;

    var_dump($text_outside);
    echo "\n\n";
    var_dump($text_inside);
  }

Вывод: extract_text («привет как дела?»); произведет:

array(1) {
  [0]=>
  string(18) "hello how are you?"
}

array(0) {
}

extract_text ("привет [http://www.google.com/test.mp3] как дела?"); будет производить

array(2) {
  [0]=>
  string(6) "hello "
  [1]=>
  string(13) " how are you?"
}


array(1) {
  [0]=>
  string(30) "http://www.google.com/test.mp3"
}
Сачин Мурали Дж.
источник
+1 но как сделать то же самое для [* и *]? Потому что [] можно использовать, например, только в html.
Майк Кастро Демария
1

Эта функция может быть полезной.

    public static function getStringBetween($str,$from,$to, $withFromAndTo = false)
    {
       $sub = substr($str, strpos($str,$from)+strlen($from),strlen($str));
       if ($withFromAndTo)
         return $from . substr($sub,0, strrpos($sub,$to)) . $to;
       else
         return substr($sub,0, strrpos($sub,$to));
    }
    $inputString = "ignore everything except this (text)";
    $outputString = getStringBetween($inputString, '(', ')'));
    echo $outputString; 
    //output will be test

    $outputString = getStringBetween($inputString, '(', ')', true));
    echo $outputString; 
    //output will be (test)

strpos () =>, который используется для поиска позиции первого появления в строке.

strrpos () =>, который используется для поиска позиции первого появления в строке.

виджей
источник
1

Уже опубликованные решения с регулярными выражениями - \((.*?)\)и \(([^\)]+)\)- не возвращают самые внутренние строки между открытыми и закрытыми скобками. Если строка Text (abc(xyz 123)они и возвращают(abc(xyz 123) как весь матч, а не (xyz 123).

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

\([^()]*\)

Или вы хотите получить значения без скобок:

\(([^()]*)\)        // get Group 1 values after a successful call to preg_match_all, see code below
\(\K[^()]*(?=\))    // this and the one below get the values without parentheses as whole matches 
(?<=\()[^()]*(?=\)) // less efficient, not recommended

Замените *на, +если между (и должен быть хотя бы 1 символ ).

Детали :

  • \( - открывающая круглая скобка (должна быть экранирована, чтобы обозначить буквальную круглую скобку, поскольку она используется вне класса символов)
  • [^()]*- ноль или больше символов , кроме (и )(обратите внимание , это (и )не должны быть экранированы внутри класса символов , как внутри него, (и )не может быть использован для указания группирования и рассматриваются в качестве буквальных скобках)
  • \) - закрывающая круглая скобка (должна быть экранирована, чтобы обозначить буквальную круглую скобку, поскольку она используется вне класса символов).

\(\KУчастие в альтернативных матчах регулярных выражений (и опускают от значения матча (с \Kоператором сброса матча). (?<=\()- это положительный просмотр назад, который требует, чтобы a (появлялся сразу слева от текущего местоположения, но (не добавляется к значению соответствия, поскольку шаблоны просмотра назад (lookaround) не используются. (?=\()- это положительный просмотр вперед, который требует, чтобы )символ появлялся сразу справа от текущего местоположения.

Код PHP :

$fullString = 'ignore everything except this (text) and (that (text here))';
if (preg_match_all('~\(([^()]*)\)~', $fullString, $matches)) {
    print_r($matches[0]); // Get whole match values
    print_r($matches[1]); // Get Group 1 values
}

Вывод:

Array ( [0] => (text)  [1] => (text here) )
Array ( [0] => text    [1] => text here   )
Виктор Стрибьев
источник
0
function getStringsBetween($str, $start='[', $end=']', $with_from_to=true){
$arr = [];
$last_pos = 0;
$last_pos = strpos($str, $start, $last_pos);
while ($last_pos !== false) {
    $t = strpos($str, $end, $last_pos);
    $arr[] = ($with_from_to ? $start : '').substr($str, $last_pos + 1, $t - $last_pos - 1).($with_from_to ? $end : '');
    $last_pos = strpos($str, $start, $last_pos+1);
}
return $arr; }

это небольшое улучшение предыдущего ответа, который вернет все шаблоны в виде массива:

getStringsBetween ('[T] his [] is [test] string [pattern]') вернет:

user628176
источник
0

Я думаю, что это самый быстрый способ получить слова между первой круглой скобкой в ​​строке.

$string = 'ignore everything except this (text)';
$string = explode(')', (explode('(', $string)[1]))[0];
echo $string;
rüff0
источник