Javascript:负面lookbehind等效?
有没有一种方法来实现JavaScript正则expression式中的消极lookbehind ? 我需要匹配一个string不是以一组特定的字符开始的。
看来我无法find一个正则expression式,如果在string的开头find匹配的部分,不会失败。 负面的反向似乎是唯一的答案,但JavaScript没有。
编辑:这是我想工作的正则expression式,但它不:
(?<!([abcdefg]))m
所以它会匹配'jim'或'm'中的'm',而不是'jam'
使用
newString = string.replace(/([abcdefg])?m/, function($0,$1){ return $1?$0:'m';});
由于Javascript支持负向预测 ,所以一个安全的方法是:
假设你想要这样做
(?<!([abcdefg]))m
- 反转string以匹配
-
使用向前的方式应用你的模式“逆向”(注意前方内部的反转匹配expression式,在这种情况下,它保持不变)
m(?!([abcdefg]))
-
反转所有匹配的标记
例子:
我定义了以下function:
const reverse = s => s.split('').reverse().join(''); const test = (stringToTests, reversedRegexp) => stringToTests .map(reverse) .forEach((s,i) => { const match = reversedRegexp.test(s); console.log( stringToTests[i], match, 'token:', match ? reverse(reversedRegexp.exec(s)[0]) : 'Ø' ); });
例1:
继安德鲁 – 艾斯利的问题之后,
test(['jim', 'm', 'jam'], /m(?!([abcdefg]))/)
输出:
jim true token: m m true token: m jam false token: Ø
例2:
在@neaumusic评论(匹配max-height
但不是line-height
,令牌height
):
test(['max-height', 'line-height'], /thgieh(?!(-enil))/)
输出:
max-height true token: height line-height false token: Ø
Mijoja的策略适用于您的具体情况,但不是一般情况:
js>newString = "Fall ball bill balll llama".replace(/(ba)?ll/g, function($0,$1){ return $1?$0:"[match]";}); Fa[match] ball bi[match] balll [match]ama
下面是一个例子,其目标是匹配一个double-l,但如果前面是“ba”,则不会。 请注意“balll”这个词 – 真正的逆转应该是压制了前两个,但是与第二个匹配。 但是,通过匹配前两个匹配,然后忽略该匹配作为误报,则正则expression式引擎从该匹配结束进行,并忽略误报内的任何字符。
假设你想要find所有的int
而不是前面的unsigned
:
支持消极的后顾之忧:
(?<!unsigned )int
没有支持消极的后顾之忧:
((?!unsigned ).{9}|^.{0,8})int
基本的想法是抓取n个前面的字符,排除负向前瞻的匹配,但也匹配没有前n个字符的情况。 (其中n是后顾长度)。
所以正确的正则expression式:
(?<!([abcdefg]))m
将转化为:
((?!([abcdefg])).|^)m
您可能需要使用捕获组来查找感兴趣的string的确切位置,或者您想用其他方法replace特定部分。
你可以通过否定字符集来定义一个非捕获组:
(?:[^ag])m
…这将匹配每个没有任何这些字母前面的m
。
遵循Mijoja的想法,并从JasonS揭露的问题中得出这个想法。 我检查了一下,但不知道我自己,所以比js正则expression式更专家的validation将是伟大的:)
var re = /(?=(..|^.?)(ll))/g // matches empty string position // whenever this position is followed by // a string of length equal or inferior (in case of "^") // to "lookbehind" value // + actual value we would want to match , str = "Fall ball bill balll llama" , str_done = str , len_difference = 0 , doer = function (where_in_str, to_replace) { str_done = str_done.slice(0, where_in_str + len_difference) + "[match]" + str_done.slice(where_in_str + len_difference + to_replace.length) len_difference = str_done.length - str.length /* if str smaller: len_difference will be positive else will be negative */ } /* the actual function that would do whatever we want to do with the matches; this above is only an example from Jason's */ /* function input of .replace(), only there to test the value of $behind and if negative, call doer() with interesting parameters */ , checker = function ($match, $behind, $after, $where, $str) { if ($behind !== "ba") doer ( $where + $behind.length , $after /* one will choose the interesting arguments to give to the doer, it's only an example */ ) return $match // empty string anyhow, but well } str.replace(re, checker) console.log(str_done)
我的个人输出:
Fa[match] ball bi[match] bal[match] [match]ama
原则是在任何两个字符之间的string中的每个点上调用checker
,只要该位置是以下位置的起点:
—任何不想要的大小的任何子string(这里是'ba'
,因此..
)(如果这个大小是已知的,否则它可能更难)
— —如果它是string的开头,那么比它更小: ^.?
在此之后,
—什么是实际寻找(这里'll'
)。
在每次调用checker
,都会有一个testing来检查ll
之前的值是不是我们不想要的( !== 'ba'
); 如果是这样的话,我们调用另一个函数,并且它将必须是这个( doer
),它将在str上进行更改,如果目的是这个,或者更一般地,将会input必要的数据来手动处理str
的扫描结果。
在这里我们改变了string,所以我们需要保留一段长度的差异,以便抵消replace
给定的位置,所有这些都是在str
计算的,而str
本身从不改变。
由于原始string是不可变的,所以我们可以使用variablesstr
来存储整个操作的结果,但是我认为已经被更换复杂化的例子会更清晰地与另一个variables( str_done
)相关联。
我认为在表演方面,它必须是相当苛刻的:所有那些毫无意义的replace成'', this str.length-1
倍,再加上这里手工更换doer,这意味着很多切片…可能在这个特定的上面的情况,可以通过将string切割成一个一圈的forms,在我们想要插入[match]
和.join()
与[match]
本身。
另一件事是,我不知道它将如何处理更复杂的情况,也就是说,复杂的价值观的虚假lookbehind …长度可能是最有问题的数据得到。
并且在checker
,如果$后面有多个可能的不需要的值,我们将不得不对另一个正则expression式进行一个testing(在caching(创build)外部checker
是最好的,以避免相同的正则expression式对象每次打电话给checker
时都会被创build出来)来知道是否我们试图避免。
希望我已经清楚了; 如果不是不犹豫,我会更好的尝试。 🙂
这有效地做到了
"jim".match(/[^ag]m/) > ["im"] "jam".match(/[^ag]m/) > null
search并replace示例
"jim jam".replace(/([^ag])m/g, "$1M") > "jiM jam"
请注意负面的后视string必须是1个字符长这个工作。
/(?![abcdefg])[^abcdefg]m/gi
是这是一个技巧。
这可能会有所帮助,具体取决于上下文:
这匹配在吉姆m,但不是果酱:
"jim jam".replace(/[ag]m/g, "").match(/m/g)