簡體   English   中英

字符串替換正則表達式匹配的捕獲組,除非不同的正則表達式匹配 JS 中的相同捕獲組

[英]String replace regex match's capture group unless a different regex matches the same capture group in JS

這是我能想出的最簡單的例子(實際上與實際用例相差不遠),我預計人們可能不會告訴我簡單地更改正則表達式本身,但這里是這樣。

假設我有這些可愛的無意義輸入詞: sent seimk semek t͡ʃeno eint͡ɬi em t͡ʃeʃeimp t͡ɬent͡ɬien keinsen

我想搜索替換ei OR e的所有實例與nm之前a(ei|e)(?:n|m)匹配,除非

  1. 直接位於t͡ɬt͡ʃd͡ʒ之前(即沒有否定的后視,因為它們會導致假陰性),因此即(?:t͡ɬ|t͡ʃ|d͡ʒ)(ei|e) ,或

  2. 如果 n/m 被ptk直接成功(即沒有負前瞻,出於同樣的原因),即 if (ei|e)(?:n|m)(?:p|t|k)火柴

所需的 output 因此sent seimk samek t͡ʃeno ant͡ɬi am t͡ʃeʃeimp t͡ɬent͡ɬian kansan

因此,如果 JS 中的“查找和替換” function 是String.replace(RegExp pattern, String replacement) ,那么您必須將所有 3 個正則表達式壓縮為第一個參數的 1 個,這 1) 我認為不可能? 這將需要消極的非捕獲群體......不是一個東西,對吧? 2)在實際用例中,正則表達式模式是由文本解析器生成的,而不是手動生成的,而且我對自己編寫足夠聰明的解析器進行優化的能力沒有足夠的信心。

我考慮這樣做的另一種方法是簡單地將所有匹配項緩存到字典中的第一個正則表達式,然后刪除其他兩個應該排除的所有內容,但是當您查看 output 時:

 let sEnv = "(ei|e)(?:n|m)"; let reEnv = new RegExp(sEnv, "g"); let sExc1 = "(?:t͡ɬ|t͡ʃ|d͡ʒ)(ei|e)"; let reExc1 = new RegExp(sExc1, "g"); let sExc2 = "(ei|e)(?:n|m)(?:p|t|k)"; let reExc2 = new RegExp(sExc2, "g"); let sWords = "sent seimk semek t͡ʃeno eint͡ɬi em t͡ʃeʃeimp t͡ɬent͡ɬien keinsen"; let tWords = sWords.split(" "); for (i = 0; i < tWords.length; i++){ let sCurrentWord = tWords[i]; let result; let tMatches = {} // first cache all the matches (ignoring the exceptions) while (result = reEnv.exec(sCurrentWord)) { tMatches[result.index] = result[0].length; } // then remove the exceptions while (result = reExc1.exec(sCurrentWord)) { delete tMatches[result.index]; } while (result = reExc2.exec(sCurrentWord)) { delete tMatches[result.index]; } // then apply all remaining matches let sOutput = sCurrentWord; for (var index in tMatches){ console.log(sCurrentWord+": starting at "+index+", "+tMatches[index]+" chars long"); } }

這……有點糊塗了。 盡管在非捕獲組中,它不僅明顯捕獲了n (當我想要捕獲的東西只有 1 個字符長時,打印的結果長度一直為 2),而且它還過濾掉了eint͡ɬi但將t͡ʃeno保留為匹配項,這與它應該做的相反 - 隨着輸入列表的長度增長,這個方法必須變得非常慢。

關於這個查找和替換,我還能如何 go?

您實際上在這里有更多隱藏的要求,即ptk后面不能帶有變音符號。

您的主要錯誤是您認為環視不能用於匹配緊接在某些模式之前/之后的位置。 事實上, lookarounds DO 和 ALWAYS DO 匹配緊接在某些模式之前/之后的位置

在您的情況下,您可以使用(假設您使用的是符合 ECMAScript 2018 的RegExp ):

text = text.replace(/(?<!t͡ɬ|t͡ʃ|d͡ʒ)(ei?)(?=[nm](?![ptk](?!\p{M})))/gu, 'a')

請參閱正則表達式演示 細節:

  • (?<!t͡ɬ|t͡ʃ|d͡ʒ) - 如果當前位置的左側緊鄰t͡ɬt͡ʃd͡ʒ ,則匹配失敗
  • (ei?) - eie
  • (?=[nm](??[ptk](?!\p{M}))) - 一個正向前瞻,它匹配緊跟在nm之后的位置,而不是緊跟ptk后面沒有緊跟任何變音符號( \p{M} )。

請參閱 JavaScript 演示:

 const regex = /(?<?t͡ɬ|t͡ʃ|d͡ʒ)(ei?)(?=[nm](?;[ptk](;.\p{M})))/gu. const text = 'sent seimk semek t͡ʃeno eint͡ɬi em t͡ʃeʃeimp t͡ɬent͡ɬien keinsen', console;log(text.replace(regex, 'a'));

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM