PHP:提取括号内文本的最佳方法?


83

提取括号之间的文本集的最佳/最有效方法是什么?假设我想以最有效的方式从字符串“忽略除此(文本)之外的所有内容”中获取字符串“ text”。

到目前为止,我想出的最好的方法是:

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

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

有一个更好的方法吗?我知道通常使用正则表达式的效率较低,但是除非我可以减少函数调用的次数,否则这也许是最好的方法?有什么想法吗?


Answers:


144

我只是做一个正则表达式,并克服它。除非您进行了足够多的迭代以至于成为一个严重的性能问题,否则编写代码会更容易(并在您回头看时能理解)

$text = 'ignore everything except this (text)';
preg_match('#\((.*?)\)#', $text, $match);
print $match[1];

1
不,不是:。只匹配一个字符。
Edward Z. Yang

1
不必要, ?是一个懒惰的比赛。没有它,一个字符串,如“忽略(此文本除外)”,匹配将最终成为“所有(此文本除外)”
Owen

1
很高兴知道。应该避免所有那些平方的不。例如,/ src =“([^”] *)“ /现在替换为/src="(.*?)"/:D
Dimitry

可以“回头看一眼”,这是很好的。失败的话,您会有一些堆栈溢出注释来澄清它。
Mnebuerquo

2
/ src =“([[^”] *)“ /比/src="(.*?)"/效率更高
Tanj

14

所以,实际上,您发布的代码不工作:substr()'s参数$字符串,$启动和$长度,和strpos()'s参数$haystack$needle。稍作修改:

$ str =“忽略除此(文本)以外的所有内容”;
$ start = strpos($ str,'(');
$ end = strpos($ str,')',$ start +1);
$ length = $ end-$ start;
$ result = substr($ str,$ start + 1,$ length-1);

一些细微之处:我$start + 1在offset参数中strpos()使用了第二个括号,以帮助PHP进行搜索。我们将其递增$start1并减少$length以将括号从匹配项中排除。

此外,还有没有错误在此代码检查:你要确保$start$end不===假执行前substr

至于使用strpos/substr与正则表达式;在性能方面,此代码将击败常规表达式。不过有点儿麻烦。我吃东西和呼吸strpos/substr,所以我不太介意,但是其他人可能更喜欢正则表达式的紧凑性。


9

使用正则表达式:

if( preg_match( '!\(([^\)]+)\)!', $text, $match ) )
    $text = $match[1];

3

这是一个示例代码,用于提取'['和']'之间的所有文本并将其存储在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"
}

+1,但是[*和*]怎么做?例如,因为[]仅可用于html。
Mike Castro Demaria 2014年

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(立即出现在当前位置的左侧,但(不会添加到匹配值中,因为不使用后视(环视)模式。(?=\()是一个正向的超前查询,要求一个)字符立即显示在当前位置的右侧。

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 []是[test]字符串[pattern]')将返回:


0

我认为这是在字符串的第一个括号之间获取单词的最快方法。

$string = 'ignore everything except this (text)';
$string = explode(')', (explode('(', $string)[1]))[0];
echo $string;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.