我需要一个正则表达式来选择两个外括号之间的所有文本。

例子: START_TEXT(这里的文本(可能的文本)文本(可能的文本(更多的文本))END_TXT ^ ^

结果: (此处文本(可能的文本)文本(可能的文本(更多的文本)))


当前回答

因为js regex不支持递归匹配,我不能使平衡括号匹配工作。

这是一个简单的javascript循环版本,将“method(arg)”字符串转换为数组

push(number) map(test(a(a()))) bass(wow, abc)
$$(groups) filter({ type: 'ORGANIZATION', isDisabled: { $ne: true } }) pickBy(_id, type) map(test()) as(groups)
const parser = str => {
  let ops = []
  let method, arg
  let isMethod = true
  let open = []

  for (const char of str) {
    // skip whitespace
    if (char === ' ') continue

    // append method or arg string
    if (char !== '(' && char !== ')') {
      if (isMethod) {
        (method ? (method += char) : (method = char))
      } else {
        (arg ? (arg += char) : (arg = char))
      }
    }

    if (char === '(') {
      // nested parenthesis should be a part of arg
      if (!isMethod) arg += char
      isMethod = false
      open.push(char)
    } else if (char === ')') {
      open.pop()
      // check end of arg
      if (open.length < 1) {
        isMethod = true
        ops.push({ method, arg })
        method = arg = undefined
      } else {
        arg += char
      }
    }
  }

  return ops
}

// const test = parser(`$$(groups) filter({ type: 'ORGANIZATION', isDisabled: { $ne: true } }) pickBy(_id, type) map(test()) as(groups)`)
const test = parser(`push(number) map(test(a(a()))) bass(wow, abc)`)

console.log(test)

结果就像

[ { method: 'push', arg: 'number' },
  { method: 'map', arg: 'test(a(a()))' },
  { method: 'bass', arg: 'wow,abc' } ]
[ { method: '$$', arg: 'groups' },
  { method: 'filter',
    arg: '{type:\'ORGANIZATION\',isDisabled:{$ne:true}}' },
  { method: 'pickBy', arg: '_id,type' },
  { method: 'map', arg: 'test()' },
  { method: 'as', arg: 'groups' } ]

其他回答

因为js regex不支持递归匹配,我不能使平衡括号匹配工作。

这是一个简单的javascript循环版本,将“method(arg)”字符串转换为数组

push(number) map(test(a(a()))) bass(wow, abc)
$$(groups) filter({ type: 'ORGANIZATION', isDisabled: { $ne: true } }) pickBy(_id, type) map(test()) as(groups)
const parser = str => {
  let ops = []
  let method, arg
  let isMethod = true
  let open = []

  for (const char of str) {
    // skip whitespace
    if (char === ' ') continue

    // append method or arg string
    if (char !== '(' && char !== ')') {
      if (isMethod) {
        (method ? (method += char) : (method = char))
      } else {
        (arg ? (arg += char) : (arg = char))
      }
    }

    if (char === '(') {
      // nested parenthesis should be a part of arg
      if (!isMethod) arg += char
      isMethod = false
      open.push(char)
    } else if (char === ')') {
      open.pop()
      // check end of arg
      if (open.length < 1) {
        isMethod = true
        ops.push({ method, arg })
        method = arg = undefined
      } else {
        arg += char
      }
    }
  }

  return ops
}

// const test = parser(`$$(groups) filter({ type: 'ORGANIZATION', isDisabled: { $ne: true } }) pickBy(_id, type) map(test()) as(groups)`)
const test = parser(`push(number) map(test(a(a()))) bass(wow, abc)`)

console.log(test)

结果就像

[ { method: 'push', arg: 'number' },
  { method: 'map', arg: 'test(a(a()))' },
  { method: 'bass', arg: 'wow,abc' } ]
[ { method: '$$', arg: 'groups' },
  { method: 'filter',
    arg: '{type:\'ORGANIZATION\',isDisabled:{$ne:true}}' },
  { method: 'pickBy', arg: '_id,type' },
  { method: 'map', arg: 'test()' },
  { method: 'as', arg: 'groups' } ]

答案取决于您是需要匹配括号的匹配集,还是只需要匹配输入文本中的第一个开始到最后一个结束的括号。

如果您需要匹配匹配的嵌套括号,那么您需要的不仅仅是正则表达式。-见@dehmann

如果只是先开后关,再见@扎克

决定你想要发生什么:

abc ( 123 ( foobar ) def ) xyz ) ghij

您需要决定在这种情况下您的代码需要匹配什么。

你可以使用regex递归:

\(([^()]|(?R))*\)

这并没有完全解决OP问题,但我认为它可能对一些来这里搜索嵌套结构regexp的人有用:

在javascript中从函数字符串(带有嵌套结构)解析参数

匹配结构如下:

匹配方括号、方括号、圆括号、单引号和双引号

在这里您可以看到生成的regexp正在运行

/**
 * get param content of function string.
 * only params string should be provided without parentheses
 * WORK even if some/all params are not set
 * @return [param1, param2, param3]
 */
exports.getParamsSAFE = (str, nbParams = 3) => {
    const nextParamReg = /^\s*((?:(?:['"([{](?:[^'"()[\]{}]*?|['"([{](?:[^'"()[\]{}]*?|['"([{][^'"()[\]{}]*?['")}\]])*?['")}\]])*?['")}\]])|[^,])*?)\s*(?:,|$)/;
    const params = [];
    while (str.length) { // this is to avoid a BIG performance issue in javascript regexp engine
        str = str.replace(nextParamReg, (full, p1) => {
            params.push(p1);
            return '';
        });
    }
    return params;
};

这个答案解释了为什么正则表达式不是这项任务的正确工具的理论局限性。


正则表达式不能做到这一点。

正则表达式基于有限状态自动机(FSA)的计算模型。顾名思义,FSA只能记住当前状态,它没有关于以前状态的信息。

在上图中,S1和S2是两种状态,其中S1是开始和结束步骤。因此,如果我们尝试使用字符串0110,转换如下:

      0     1     1     0
-> S1 -> S2 -> S2 -> S2 ->S1

在上述步骤中,当我们在第二个S2,即解析完0110的01之后,FSA没有关于01中前一个0的信息,因为它只能记住当前状态和下一个输入符号。

在上面的问题中,我们需要知道左括号的no;这意味着它必须存储在某个地方。但是由于fsa不能这样做,因此不能编写正则表达式。

但是,可以编写一个算法来完成这项任务。算法一般属于下推自动机(PDA)。PDA比FSA高一级。PDA有一个额外的堆栈来存储一些额外的信息。pda可以用来解决上述问题,因为我们可以在堆栈中“推入”开括号,并在遇到闭括号时“弹出”它们。如果在结束时,堆栈为空,则开始括号和结束括号匹配。否则不。