代码之家  ›  专栏  ›  技术社区  ›  Alk

在JavaScript替代方案中的regex lookback

  •  0
  • Alk  · 技术社区  · 6 年前

    我尝试在JS中使用以下regex:

    (?<=@[A-Z|a-z]+,)\s|(?<=@[A-Z|a-z]+,\s[A-Z|a-z]+)\s(?=\[[A-Z|a-z]+\])

    也就是说:

    匹配前面的所有空格:

    • @
    • 后跟范围内的任意字符数 A-Z a-z
    • 后跟逗号

    匹配前面的所有空格:

    • @

    • 后跟范围内的任意字符数 阿兹 阿兹

    • 后跟逗号
    • 后面是空格
    • 后跟范围内的任意字符数 阿兹 阿兹

    并由以下人员继承:

    • [
    • 后跟范围内的任意字符数 阿兹 阿兹
    • ]

    但是,JS不支持lookback。在JS或我可以使用的任何NPM库中,是否有其他方法来支持上述regex?

    所以如果我们有这样的句子
    Hi my name is @John, Doe [Example] and I am happy to be here 那应该变成
    Hi my name is @John,Doe[Example] and I am happy to be here .
    另外,如果我们有
    Hi my name is @John, Smith Doe [Example] ,应该是
    Hi my name is @John,SmithDoe[Example] .

    3 回复  |  直到 6 年前
        1
  •  2
  •   yunzen    6 年前

    我已经更新了新输入的答案

    console.clear();
    
    var inputEl = document.querySelector('#input')
    var outputEl = document.querySelector('#output')
    
    function rep (e) {
      var input = e.target.value;
      var reg = /@([a-z]+?\s*?)+,(\s+[a-z]+)+(\s\[[a-z]+\])?/gim
    
    
    
      matches = input.match(reg);
      var output = input;
    
      if (matches) {
        replaceMap = new Map()
        for (var i = 0; i < matches.length; i++) {
          var m = matches[i]
            .replace(/\[/, '\\[')
            .replace(/\]/, '\\]')
          replaceMap.set(m, matches[i].replace(/\s+/gm, ''))
        }
        for (var [s,r] of replaceMap) {
          output = output.replace(new RegExp(s, 'gm'), r) 
        }
      }
    
      outputEl.textContent = output
    }
    
    inputEl.addEventListener('input', rep)
    inputEl.dispatchEvent(new Event('input'))
    textarea {
      width: 100%; 
      min-height: 100px;
    }
    <h3>Input</h3>
    <textarea id="input">@Lopez de la Cerda, Antonio Gabriel Hugo David [Author]. I'm the father of @Marquez, Maria</textarea>
    <h3>Output (initially empty)</h3>
    <p id="output"></p>
    <h3>Expected result (on initial input)</h3>
    <p>@LopezdelaCerda,AntonioGabrielHugoDavid[Author]. I'm the father of @Marquez,Maria</p>

    旧答案内容的备份(出于历史原因)

    它至少在Chrome中与此regex一起工作:

    /(?<=@[a-z]+,)\s+(?![a-z]+\s+\[[a-z]+\])|(?<=(@[a-z]+,\s[a-z]+))\s+(?=\[[a-z]+\])/gmi
    

    见: https://regex101.com/r/elTkRe/4

    但是你不能在PCRE中使用它,因为在lookbehinds中不允许有量词。它们必须具有固定宽度。请参见此处右侧的错误: https://regex101.com/r/ZC3XmX/2

    解决办法不看后面看前面

    console.clear();
    
    var reg = /(@[A-Za-z]+,\s[A-Za-z]+)(\s+)(\[[A-Za-z]+\])|(@[A-Z|a-z]+,)(\s+)/gm
    
    var probes = [
      '@gotAMatch,     <<<',
      '@LongerWithMatch,        <<<',
      '@MatchHereAsWell,    <<<',
      '@Yup,         <<<<',
      '@noMatchInThisLine,<<<<<',
      '@match, match    [match]<<<<<<<',
      '@    noMatchInThisLine,    <<<<'
    ]
    
    for (var i in probes) {
      console.log(probes[i].replace(reg, '$1$3$4'))
    }
    .as-console-wrapper { max-height: 100% !important; top: 0; }
        2
  •  1
  •   revo shanwije    6 年前

    您需要做的是将lookbehind转换为捕获组,以便将它们包含在替换字符串中(请注意,不区分大小写的标志( i ):

    (@[a-z]+,)([\t ]*([a-z]+)[\t ]*(?=\[[a-z]+\])|[\t ]+)
    

    替换为 $1$3 如果要删除这些空格。

    live demo here

        3
  •  0
  •   wortwart    6 年前

    只需更新node.js版本。Lookback断言是ECMAScript 2018的一部分,已经在chromium和node.js中实现。根据 http://kangax.github.io/compat-table/es2016plus/ ,chromium 70和node.js 8.10具有此功能。

    我刚在浏览器和node.js(V8.11)中测试过它,可以确认:

    node -e "console.log('nothing@xyz, bla'.match(/(?<=@[A-Za-z]+,)\s+/))"
    

    如果无法更新,则必须使用其他策略,如捕获和替换,这不应是一个大问题,而是采用积极的后视(消极的情况更难做到):

    const hit = 'nothing@xyz, bla'.match(/(@[A-Za-z]+,)\s+/)
    hit[0].replace(hit[1])
    

    如果没有其他方法起作用,请看一看这个试图实现lookback的项目(我还没有测试它): http://blog.stevenlevithan.com/archives/javascript-regex-lookbehind