Javascript regex-查看后面的替代方案?

下面是一个在大多数 regex 实现中工作良好的 regex:

(?<!filename)\.js$

这与以. js 结尾的字符串. js 匹配,但 filename.js 除外

Javascript 没有 regex 后向。是否有人能够把一个替代的正则表达式放在一起,实现相同的结果,并在 javascript 中工作?

下面是一些想法,但是需要 helper 函数: Http://blog.stevenlevithan.com/archives/mimic-lookbehind-javascript

124262 次浏览

^(?!filename).+\.js为我工作

测试对象:

  • Test.js 匹配
  • 胡言乱语符合
  • Filename.js 不匹配

正则表达式匹配不包含单词的字符串?中可以找到对这个正则表达式的正确解释

前瞻自 Javascript 的1.5版本以来就可用,并且受到所有主流浏览器的支持

更新 以匹配 filename2.js 和2filename. js,但不匹配 filename.js

(^(?!filename\.js$).).+\.js

编辑: 从 ECMAScript 2018开始,本机支持后视断言(甚至是无界断言)

在以前的版本中,您可以这样做:

^(?:(?!filename\.js$).)*\.js$

这显式地执行了 lookbehind 表达式隐式执行的操作: 检查字符串中的每个字符,如果 lookbehind 表达式加上后面的正则表达式不匹配,则只允许该字符匹配。

^                 # Start of string
(?:               # Try to match the following:
(?!              # First assert that we can't match the following:
filename\.js    # filename.js
$               # and end-of-string
)                # End of negative lookahead
.                # Match any character
)*                # Repeat as needed
\.js              # Match .js
$                 # End of string

另一个编辑:

我很痛心地说(尤其是这个答案已经得到了如此多的支持) ,有一个更容易的方法来实现这个目标。没有必要检查每个字符的前瞻性:

^(?!.*filename\.js$).*\.js$

效果一样好:

^                 # Start of string
(?!               # Assert that we can't match the following:
.*               # any string,
filename\.js    # followed by filename.js
$               # and end-of-string
)                 # End of negative lookahead
.*                # Match any string
\.js              # Match .js
$                 # End of string

让我们假设您希望找到所有 int之前没有 unsigned的内容:

支持负面回顾:

(?<!unsigned )int

没有负面回顾的支持:

((?!unsigned ).{9}|^.{0,8})int

基本思想是获取前面的 n 个字符,并使用负向查找排除 match,但也要匹配前面没有 n 个字符的情况。(其中 n 表示向后看的长度)。

因此,我们讨论的正则表达式是:

(?<!filename)\.js$

就是说:

((?!filename).{8}|^.{0,7})\.js$

您可能需要使用捕获组来找到您感兴趣的字符串的确切位置,或者不想用其他东西替换特定部分。

如果你可以向前看但是向后看,你可以先反转字符串,然后再向前看。当然,还需要做更多的工作。

下面是对 JavaScript 替代方案的一个积极的看法,展示了如何捕获以“ Michael”作为姓氏的人的姓氏。

1)鉴于以下文字:

const exampleText = "Michael, how are you? - Cool, how is John Williamns and Michael Jordan? I don't know but Michael Johnson is fine. Michael do you still score points with LeBron James, Michael Green Miller and Michael Wood?";

得到一系列叫迈克尔的人的姓氏。 结果应该是: ["Jordan","Johnson","Green","Wood"]

2)解决方案:

function getMichaelLastName2(text) {
return text
.match(/(?:Michael )([A-Z][a-z]+)/g)
.map(person => person.slice(person.indexOf(' ')+1));
}


// or even
.map(person => person.slice(8)); // since we know the length of "Michael "

3)检查溶液

console.log(JSON.stringify(    getMichaelLastName(exampleText)    ));
// ["Jordan","Johnson","Green","Wood"]

演示: http://codepen.io/PiotrBerebecki/pen/GjwRoo

您也可以通过运行下面的代码片段来尝试使用它。

const inputText = "Michael, how are you? - Cool, how is John Williamns and Michael Jordan? I don't know but Michael Johnson is fine. Michael do you still score points with LeBron James, Michael Green Miller and Michael Wood?";






function getMichaelLastName(text) {
return text
.match(/(?:Michael )([A-Z][a-z]+)/g)
.map(person => person.slice(8));
}


console.log(JSON.stringify(    getMichaelLastName(inputText)    ));

这是与 Tim Pietzcker 的回答等价的解决方案(请参阅同一答案的注释) :

^(?!.*filename\.js$).*\.js$

它的意思是,除了 *filename.js,匹配 *.js

要获得这个解决方案,您可以检查负向查找排除了哪些模式,然后使用负向查找排除这些模式。

谢谢 Tim Pietzcker 和其他人的回答。他们的作品给了我很大的启发。然而,我认为没有任何理想的解决方案可以模仿后视镜。例如,来自 Pietzcker 的解决方案受到 $的限制,就像在线一样,也就是说,如果没有 $,就会得到意想不到的结果:

let str="filename.js  main.js  2022.07.01"
console.log( /^(?!.*filename\.js).*\.js/g.exec(str) ) //null

另一个限制是很难翻译多重后视,例如:

let reg=/(?<!exP0)exp0 \d (?<!exP1)exp1 \d (?<!exP2)exp2/

如何建立一个更多的 普通的,免费的方法来使用后向断言替代? 下面是我的解决方案。

替代代码的核心模式是:

(?:(?!ExpB)....|^.{0,3})ExpA <= (?<!ExpB)ExpA

详细解释:

(?:         # start an unsave group:
(?!ExpB)   # Assert a possion who can't match the ExpB
....       # Any string, the same length as ExpB
|^.{0,3}   # Or match any string whoes length is less than ExpB
)           # End of negative lookahead
ExpA        # Match ExpA

例如:

var str="file.js  main.js  2022.07.01"
var reg=/(?:(?!file)....|^.{0,3})\.js/g // <= (?<!file)\.js
console.log( reg.exec(str)[0] )  // main.js

这里有一个工具可以将上述模式转化为糖:

var str="file.js  main.js  2022.07.01"
var reg=newReg("﹤4?!file﹥\\.js","g") //pattern sugar
console.log(reg.exec(str)[0]) // main.js


function newReg(sReg,flags){
flags=flags||""
sReg=sReg.replace(/(^|[^\\])\\﹤/g,"$1<_sl_>").replace(/(^|[^\\])\\﹥/g,"$1<_sr_>")
if (/﹤\?<?([=!])(.+?)﹥/.test(sReg)){
throw "invalid format of string for lookbehind regExp"
}
var reg=/﹤(\d+)\?<?([=!])(.+?)﹥/g
if (sReg.match(reg)){
sReg=sReg.replace(reg, function(p0,p1,p2,p3){
return "(?:(?"+p2+p3+")"+".".repeat(parseInt(p1))+"|^.{0,"+(parseInt(p1)-1)+"})"
})
}
sReg=sReg.replace(/<_sl_>/g,"﹤").replace(/<_sr_>/g,"﹥")
var rr=new RegExp(sReg,flags)
return rr
}

使用两个特殊字符 (\uFE64 or &#65124;)和 (\uFE65 or &#65125;)封装后向表达式,计算后向表达式长度的数字 N必须跟在 后面。也就是说,lookbehind 的语法是:

﹤N?!ExpB﹥ExpA <= (?<!ExpB)ExpA
﹤N?=ExpB﹥ExpA <= (?<=ExpB)ExpA

为了使上面的模式更像 ES5,您可以用括号替换 ,并删除 N,将更多代码写入 newReg()函数。