regex - Negatívny lookbehind ekvivalent v JavaScripte
Existuje spôsob, ako dosiahnuť ekvivalent negatívneho lookbehindu v regulárnych výrazoch JavaScriptu? Potrebujem zistiť reťazec, ktorý nezačína konkrétnym súborom znakov.
Zdá sa, že nedokážem nájsť regulárny výraz, ktorý by to spravil bez toho, aby zlyhal, ak je zodpovedajúca časť nájdená na začiatku reťazca. Negatívne spätne hľadania sa zdajú byť jedinou odpoveďou, ale JavaScript ich nemá.
Toto je regex, ktorý by som chcel, aby fungoval, ale nefunguje:
(?<!([abcdefg]))mTakže by sa to zhodovalo s 'm' v 'jim' alebo 'm', ale nie s 'jam'
Odpoveď č. 1
Od roku 2018 sú spätné kontroly súčasťou špecifikácie jazyka ECMAScript.
// positive lookbehind
(?<=...)
// negative lookbehind
(?<!...)
Odpoveď pred rokom 2018
Keďže Javascript podporuje negatívny lookahead, jedným zo spôsobov, ako to urobiť, je:
otoči vstupný reťazec
zodpovedať obrátenému regulárnemu výrazu
otočiť a preformátovať zápasy
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]) : 'Ø');
});
Príklad 1:
Nasledujúc otázku @andrew-ensley:
test(['jim', 'm', 'jam'], /m(?!([abcdefg]))/)
Výstupy :
jim true token: m
m true token: m
jam false token: Ø
Príklad 2:
Podľa komentára @neaumusic (zhoda s max-height, ale nie s line-height, token je height):
test(['max-height', 'line-height'], /thgieh(?!(-enil))/)
Výstupy :
max-height true token: height
line-height false token: Ø
Odpoveď č. 2
Lookbehind Assertions boli prijaté do špecifikácie ECMAScript v roku 2018.
Použitie pozitívneho lookbehindu:
console.log(
"$9.99 €8.47".match(/(?<=\$)\d+\.\d*/) // Matches "9.99"
);Použitie negatívneho lookbehindu:
console.log(
"$9.99 €8.47".match(/(?<!\$)\d+\.\d*/) // Matches "8.47"
);Podpora platforiem
✔️ V8
- ✔️ Google Chrome 62.0
- ✔️ Microsoft Edge 79.0
- ✔️ Node.js 6.0 za vlajkou a 9.0 bez vlajky
- ✔️ Deno (všetky verzie)
✔️ SpiderMonkey
- ✔️ Mozilla Firefox 78.0
✔️ JavaScriptCore: funkcia bola zlúčená
- ✔️ Apple Safari 16.4
❌ Chakra: Microsoft na tom pracoval, ale Chakra bola teraz opustená v prospech V8
- ❌ Internet Explorer
Odpoveď č. 3
Predpokladajme, že chcete nájsť všetky int, ktoré nie sú predchádzané unsigned :
S podporou pre negatívne vyhľadávanie dozadu:
(?<!unsigned )int
Bez podpory pre negatívne look-behind:
((?!unsigned ).{9}|^.{0,8})int
V podstate ide o to, aby sa zachytilo n predchádzajúcich znakov a vylúčila zhoda s negatívnym pohľadom do budúcnosti, ale zároveň sa zachytili prípady, kde neexistuje predchádzajúcich n znakov. (kde n je dĺžka pohľadu do minulosti).
Takže regulárny výraz, o ktorom je reč:
(?<!([abcdefg]))m
by sa preložilo ako:
((?!([abcdefg])).|^)m
Možno budete musieť experimentovať so zachytávacími skupinami, aby ste našli presné miesto reťazca, ktoré vás zaujíma, alebo ak chcete nahradiť konkrétnu časť niečím iným.
Odpoveď č. 4
Mijoja stratégia funguje vo vašom konkrétnom prípade, ale nie všeobecne:
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
Tu je príklad, kde je cieľom nájsť dvojité l, ale nie ak mu predchádza „ba“. Všimnite si slovo „balll“ — skutočný lookbehind by mal potlačiť prvé 2 l, ale nájsť druhú dvojicu. Ale tým, že sa najprv nájdu prvé 2 l a potom sa tento nález ignoruje ako falošný poplach, regulárny výraz pokračuje od konca tohto nálezu a ignoruje akékoľvek znaky vo vnútri falošného poplachu.
Odpoveď č. 5
Použiť
newString = string.replace(/([abcdefg])?m/, function($0,$1){ return $1?$0:'m';});
Odpoveď č. 6
Môžete definovať nekapturujúcu skupinu tak, že negujete svoju množinu znakov:
(?:[^a-g])m
...čo by zodpovedalo každému m, ktoré **nenasleduje** pred niektorým z týchto písmen.
