javascript正则表达式-寻找替代方法?

roejwanj  于 2023-01-08  发布在  Java
关注(0)|答案(8)|浏览(119)

下面是一个在大多数正则表达式实现中工作良好的正则表达式:

(?<!filename)\.js$

对于以.js结尾的字符串(文件名. js除外),这与.js匹配
Javascript没有regex lookbehind,有没有人能把一个替代的regex放在一起,达到同样的效果,并在javascript中工作?
这里有一些想法,但需要帮助函数。我希望只用一个正则表达式就能实现:http://blog.stevenlevithan.com/archives/mimic-lookbehind-javascript

c9x0cxw0

c9x0cxw01#

编辑:从ECMAScript 2018开始,lookbehind assertions (even unbounded) are supported natively
在以前的版本中,您可以执行以下操作:

^(?:(?!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
qhhrdooz

qhhrdooz2#

^(?!filename).+\.js适合我
测试对象:

  • test.js匹配
  • blabla.js匹配
  • 文件名. js不匹配

可以在Regular expression to match string not containing a word?中找到此正则表达式的正确解释
Look ahead从javascript 1.5版开始提供,所有主流浏览器都支持它

已更新以匹配文件名2.js和2filename.js,但不匹配filename.js

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

jhkqcmku

jhkqcmku3#

假设你想找到所有前面没有unsignedint
支持负后视:

(?<!unsigned )int

不支持负后视:

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

基本思想是获取前面的n个字符,并排除与负前瞻匹配,但也匹配没有前面的n个字符的情况。(其中n是前瞻的长度)。
我们讨论的正则表达式是:

(?<!filename)\.js$

将转化为:

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

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

bvk5enib

bvk5enib4#

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

mcvgt66p

mcvgt66p5#

这是Tim Pietzcker's answer的等效解决方案(另请参见相同答案的注解):

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

意思是,除了*filename.js之外,都匹配。
要获得这个解决方案,您可以检查负向后查找排除了哪些模式,然后使用负向前查找排除这些模式。

zzwlnbp8

zzwlnbp86#

感谢Tim Pietzcker等人的回答,他们的作品给了我很大的启发,但是我认为模仿lookbehind并没有一个理想的解决方案,比如Pietzcker的解决方案是以$作为EOL的限制,也就是说没有$会得到意想不到的结果:

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/

如何建立一个更通用和自由的方法来交替使用lookbehindAssert?
替代代码的核心模式是:

(?:(?!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

下面是一个将上述模式转换为sugar的实现:

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;)将lookbehind表达式括起来,并且在之后必须有一个计数lookbehind表达式长度的数字N,即lookbehind的语法为:

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

要使上面的模式更像ES5,可以用括号替换,并通过向newReg()函数中写入更多代码来删除N

mcvgt66p

mcvgt66p7#

我知道这个答案并没有真正解决如何重写正则表达式来模拟lookbehinds,但是我设法克服了一些非常简单的情况,比如这样,通过预先替换字符串中不需要的匹配,如下所示:

let string = originalString.replace("filename.js", "filename_js")
  string.match(/.*\.js/)
camsedfj

camsedfj8#

下面是一个积极的lookbehind 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?";

获取一个名为Michael的人的姓氏数组。结果应该是:第一个月
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)    ));

相关问题