PHP: лучший способ извлечь текст в круглых скобках?
Какой лучший/самый эффективный способ извлечения текста между круглыми скобками? Скажем, я хотел получить строку "текст" из строки "игнорировать все, кроме этого (текста)", наиболее эффективным способом.
Пока лучшее, что я придумал, это:
$fullString = "ignore everything except this (text)";
$start = strpos('(', $fullString);
$end = strlen($fullString) - strpos(')', $fullString);
$shortString = substr($fullString, $start, $end);
Есть ли лучший способ сделать это? Я знаю, что обычно использование регулярных выражений имеет тенденцию быть менее эффективным, но если я не могу уменьшить количество вызовов функций, возможно, это был бы лучший подход? Мысли?
Ответы
Ответ 1
Я бы просто сделал регулярное выражение и переделал его. если вы не делаете достаточно итераций, что это становится огромной проблемой производительности, ее просто проще кодировать (и понимать, когда вы оглядываетесь на нее)
$text = 'ignore everything except this (text)';
preg_match('#\((.*?)\)#', $text, $match);
print $match[1];
Ответ 2
Итак, на самом деле код, который вы опубликовали, не работает: substr()'s
параметры: $string, $start и $length, а strpos()'s
- $haystack
, $needle
, Немного изменено:
$str = "ignore everything except this (text)";
$start = strpos($str, '(');
$end = strpos($str, ')', $start + 1);
$length = $end - $start;
$result = substr($str, $start + 1, $length - 1);
Некоторые тонкости: я использовал $start + 1
в параметре offset, чтобы помочь PHP выходить во время поиска strpos()
во второй скобке; мы увеличиваем $start
один и уменьшаем $length
, чтобы исключить круглые скобки из соответствия.
Кроме того, в этом коде нет проверки ошибок: вы должны убедиться, что $start
и $end
не === false перед выполнением substr
.
Что касается использования strpos/substr
по сравнению с регулярным выражением; по производительности, этот код будет бить обычным выражением рук. Это немного словнее. Я ем и дышу strpos/substr
, поэтому я не против этого слишком много, но кто-то другой может предпочесть компактность регулярного выражения.
Ответ 3
Используйте регулярное выражение:
if( preg_match( '!\(([^\)]+)\)!', $text, $match ) )
$text = $match[1];
Ответ 4
Это пример кода для извлечения всего текста между '[' и ']' и сохранения его 2 отдельных массивов (т.е. текст внутри круглых скобок в одном массиве и текст вне скобок в другом массиве)
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"
}
Ответ 5
Эта функция может быть полезна.
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() = > , который используется для поиска позиции первого события в строке.
Ответ 6
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]') вернет:
Ответ 7
Уже опубликованные решения регулярных выражений - \((.*?)\)
И \(([^\)]+)\)
- не возвращают самые внутренние строки между открытыми и закрытыми скобками. Если строка имеет Text (abc(xyz 123)
они оба возвращают a (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
). (?<=\()
- это положительный взгляд сзади, который требует (
чтобы он появлялся слева от текущее местоположение, но (
не добавляется к значению совпадения, так как шаблоны lookbehind (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 )