5

这是我目前所拥有的......

var regex_string = "s(at)?u(?(1)r|n)day"
console.log("Before: "+regex_string)
var regex_string = regex_string.replace(/\(\?\((\d)\)(.+?\|)(.+?)\)/g,'((?!\\$1)$2\\$1$3)')
console.log("After: "+regex_string)
var rex = new RegExp(regex_string)

var arr = "thursday tuesday thuesday tursday saturday sunday surday satunday monday".split(" ")
for(i in arr){
  var m
  if(m = arr[i].match(rex)){
    console.log(m[0])
  }
}

我正在交换(?(n)a|b)where((?!\n)a|\nb)n一个数字,aandb是字符串。这似乎工作正常 - 但是,我知道这是一个很大的黑客。

有没有更好的方法来解决这个问题?

4

1 回答 1

14

在您的正则表达式的特定情况下,使用交替更简单且更具可读性:

(?:sunday|saturday)

或者,您可以仅在涉及条件正则表达式的 2 个位置之间创建交替(这在有许多此类条件表达式的情况下更有用,但仅指附近的捕获组)。以您的案例为例,我们将只为unatur因为只有那些与条件有关:

s(?:un|atur)day

有两种常见的条件正则表达式。(Perl 正则表达式支持更多奇特的东西,但这些需要支持 JavaScript 正则表达式或其他常见正则表达式引擎不具备的特性)。

  1. 第一种类型是提供显式模式作为条件。这种类型可以在 JavaScript 正则表达式中模仿。在支持条件正则表达式的语言中,模式将是:

    (?(conditional-pattern)yes-pattern|no-pattern)
    

    在 JavaScript 中,您可以通过前瞻来模仿它,并且(明显)假设原始文件conditional-pattern是前瞻:

    ((?=conditional-pattern)yes-pattern|(?!conditional-pattern)no-pattern)
    

    负前瞻是必要的,以防止输入字符串在 中通过conditional-pattern和失败的情况yes-pattern,但它可以匹配no-pattern. 这样做是安全的,因为正向环视和负向环视在逻辑上是完全相反的。

  2. 第二种类型是提供对捕获组的引用(名称或编号),当捕获组匹配时,条件将被评估为真。在这种情况下,没有简单的解决方案。

    我能想到的唯一方法是重复,就像我以您的案例为例所做的那样。这当然会降低可维护性。可以通过将它们分成部分(在文字 RegExp 中)来组成您的正则表达式,检索带有source属性的字符串,然后将它们连接在一起;这将允许更改传播到其他重复的部分,但会使理解正则表达式和/或对其进行重大修改变得更加困难。

参考

于 2013-02-22T14:14:43.907 回答