使用正则表达式获取两个括号之间有文本的括号内文本

3

在尝试了10次修改问题以被接受之后,我有一个包含括号中文本的小段落,我想要提取出这个文本,因此我编写了以下表达式:

/(\([^\)]+\))/i

但这只提取了第一个(和最后一个)之间的文本,忽略了其余的文本。那么有没有一种方法可以提取完整的文本,例如:
i want(to) extract this text

来自:

this is the text that (i want(to) extract this text) from

可能会有多个括号里面的子文本。

谢谢

编辑: 发现了这个:

preg_match_all("/\((([^()]*|(?R))*)\)/", $rejoin, $matches);

非常有用的链接,已在接受答案中提供。

请在此处查看:http://php.net/manual/zh/regexp.reference.recursive.php - elclanrs
你的一般要求是(a)从最外层括号中提取所有内容,还是(b)提取第二个最低级别的括号表达式,或者(c)其他要求?在一般情况下,你不能处理正则表达式中任意级别的嵌套,但如果你有一个固定的级别,你可能可以为其创建一个正则表达式。 - tripleee
虽然递归的 "reg"ex 可以做到这一点,但实际上编写一个轻量级解析器来处理这种用例可能更好、更易于维护。递归在 "reg"ex 中需要大量资源,性能表现不佳,即使在最佳格式中,表达式本身也可能非常模糊难懂。 - eyelidlessness
/((.*))/ 这是从这里开始的 https://dev59.com/cWIj5IYBdhLWcg3w04bd - Mrigesh Raj Shrestha
4个回答

6
是的,您可以使用这种模式。
   v                   v
 (\([^\)\(]*)+([^\)\(]*\))+
 ------------ -------------
      |            |
      |            |->match all (right)brackets to the right..
      |
      |->match all (left)brackets to the left

演示


如果您有一个像这样的递归模式,则上面的模式将无效

(i want(to) (extract and also (this)) this text)
                              ------
            -------------------------

在这种情况下,您可以使用elclanrs建议的递归模式
您也可以通过维护()数量的计数来实现无需使用正则表达式的操作。
所以, 假设noOfLB(的计数,noOfRB)的计数。
  • 保持迭代字符串中的每个字符并维护第一个(的位置
  • 如果找到(,则增加noOfLB
  • 如果找到),则增加noOfRB
  • 如果noOfLB==noOfRB,则您已经找到了最后一个)的位置
我不知道php,所以我会在c#中实现上述算法。
public static string getFirstRecursivePattern(string input)
{
    int firstB=input.IndexOf("("),noOfLB=0,noOfRB=0;
    for(int i=firstB;i<input.Length && i>=0;i++)
    {
         if(input[i]=='(')noOfLB++;
         if(input[i]==')')noOfRB++;
         if(noOfLB==noOfRB)return input.Substring(firstB,i-firstB+1);
    }
    return "";
}

2
您需要使用递归子模式来解决这个问题。以下是应该适用于您的正则表达式:

您需要使用递归子模式来解决这个问题。以下是应该适用于您的正则表达式:

$str = 'this is the text that (i want(to) extract this text) from';
if (preg_match('/\s* \( ( (?: [^()]* | (?0) )+ ) \) /x', $str, $arr))
   var_dump($arr);

输出:

string(28) "i want(to) extract this text"

“这是我想要从中提取文本的文本:‘这是我想要提取的文本’” - Rami Dabain
出于好奇,您想从输入中提取什么文本:“this is the text that (i want(to) (to) (to) (to) extract this text) from”? - anubhava
1
我的上面的解决方案将提供:我想要提取这段文本 - anubhava
是的,但它不是递归的。我想我需要一个递归的,并且答案提供了一个好的链接。我明天会通过编辑问题发布它。 - Rami Dabain
期待看到您的编辑。然而,我想再次强调,上面的答案确实是递归的,并基于此:http://php.net/manual/en/regexp.reference.recursive.php - anubhava

0

你也可以使用子字符串:

$yourString = "this is the text that (i want(to) extract this text) from";

$stringAfterFirstParen = substr( strstr( $yourString, "(" ), 1 );

$indexOfLastParen = strrpos( $stringAfterFirstParen, ")" );

$stringBetweenParens = substr( $stringAfterFirstParen, 0, $indexOfLastParen );

0

我认为我理解了这个问题,您想从类似于这样的东西中提取“我想(要)提取这个文本”或类似的内容:“这是文本,(我想(要)提取这个文本)”

如果是这样,您可以使用以下正则表达式(使用$text定义要检查的变量和$txt作为在匹配情况下创建的变量,然后将其存储在数组$t[]中):

if (preg_match('/\(\w+.+\)/', $text, $t)) {
$txt = $t[0];
} else {
$txt = "";
}
echo $desired=substr($txt,1,-1);

这个正则表达式的根是:(\w+.+),以下是代码的解释:

  1. 匹配字符“(”字面上的“(”
  2. 匹配一个单词字符(字母、数字和下划线)«\w+»,出现一次或多次,尽可能多地给出所需的内容(贪婪模式)«+»
  3. 匹配任何不是换行符的单个字符«.+»,出现一次或多次,尽可能多地给出所需的内容(贪婪模式)«+»
  4. 匹配字符“)”字面上的“)”
  5. 将括号内的文本放入新变量$desired中。通过选择一个减少了一端字符的子字符串来显示$desired字符,从而消除了边界括号。«echo $desired=substr($txt,1-1)»
使用上述方法,我能够显示:我想从变量$text = this is the text that (i want(to) extract this text) from中提取这段文本。如果想要从(to)中提取"to",建议您将变量通过正则表达式循环运行,直到在表达式中找不到更多的( )并返回一个null值,并将返回的值连接起来形成感兴趣的变量。
祝好运, 史蒂夫

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接