Před pěti lety jsem zveřejnil Napodobování Lookbehind v JavaScriptu na tomto blogu, kde jsem podrobně popsal několik způsobů, jak napodobit pozitivní a negativní vzhled v JavaScriptu. Moje tehdejší přístupy byly všechny dost drsné a bylo komplikované správně přizpůsobit kterýkoli z nich, aby fungoval s daným vzorem. Navíc byly navrženy pouze pro simulaci lookbehind v náhradě založené na regulárních výrazech.
Aby bylo používání lookbehind mnohem jednodušší, nedávno jsem na GitHub zveřejnil sbírku krátkých funkcí. Používají XRegExp v2, takže byste se na to měli také podívat.
Zde je kód:
// Simulating infinite-length leading lookbehind in JavaScript. Uses XRegExp. // Captures within lookbehind are not included in match results. Lazy // repetition in lookbehind may lead to unexpected results. (function (XRegExp) { function prepareLb(lb) { // Allow mode modifier before lookbehind var parts = /^((?:\(\?[\w$]+\))?)\(\?<([=!])([\s\S]*)\)$/.exec(lb); return { // $(?!\s) allows use of (?m) in lookbehind lb: XRegExp(parts ? parts[1] + "(?:" + parts[3] + ")$(?!\\s)" : lb), // Positive or negative lookbehind. Use positive if no lookbehind group type: parts ? parts[2] === "=" : !parts }; } XRegExp.execLb = function (str, lb, regex) { var pos = 0, match, leftContext; lb = prepareLb(lb); while (match = XRegExp.exec(str, regex, pos)) { leftContext = str.slice(0, match.index); if (lb.type === lb.lb.test(leftContext)) { return match; } pos = match.index + 1; } return null; }; XRegExp.testLb = function (str, lb, regex) { return !!XRegExp.execLb(str, lb, regex); }; XRegExp.searchLb = function (str, lb, regex) { var match = XRegExp.execLb(str, lb, regex); return match ? match.index : -1; }; XRegExp.matchAllLb = function (str, lb, regex) { var matches = [], pos = 0, match, leftContext; lb = prepareLb(lb); while (match = XRegExp.exec(str, regex, pos)) { leftContext = str.slice(0, match.index); if (lb.type === lb.lb.test(leftContext)) { matches.push(match[0]); pos = match.index + (match[0].length || 1); } else { pos = match.index + 1; } } return matches; }; XRegExp.replaceLb = function (str, lb, regex, replacement) { var output = "", pos = 0, lastEnd = 0, match, leftContext; lb = prepareLb(lb); while (match = XRegExp.exec(str, regex, pos)) { leftContext = str.slice(0, match.index); if (lb.type === lb.lb.test(leftContext)) { // Doesn't work correctly if lookahead in regex looks outside of the match output += str.slice(lastEnd, match.index) + XRegExp.replace(match[0], regex, replacement); lastEnd = match.index + match[0].length; if (!regex.global) { break; } pos = match.index + (match[0].length || 1); } else { pos = match.index + 1; } } return output + str.slice(lastEnd); }; }(XRegExp));
To je po minifikaci a gzipování méně než 0,5 kB. Poskytuje kolekci funkcí, které usnadňují emulaci předního vzhledu:
XRegExp.execLb
XRegExp.testLb
XRegExp.searchLb
XRegExp.matchAllLb
XRegExp.replaceLb
Každá z těchto funkcí má tři argumenty:řetězec, který se má hledat, vzor lookbehind jako řetězec (může používat rozšíření syntaxe XRegExp) a hlavní regulární výraz. XRegExp.replaceLb
bere čtvrtý argument pro hodnotu nahrazení, což může být řetězec nebo funkce.
Následují příklady použití:
XRegExp.execLb("Fluffy cat", "(?i)(?<=fluffy\\W+)", XRegExp("(?i)(?<first>c)at")); // -> ["cat", "c"] // Result has named backref: result.first -> "c" XRegExp.execLb("Fluffy cat", "(?i)(?<!fluffy\\W+)", /cat/i); // -> null XRegExp.testLb("Fluffy cat", "(?i)(?<=fluffy\\W+)", /cat/i); // -> true XRegExp.testLb("Fluffy cat", "(?i)(?<!fluffy\\W+)", /cat/i); // -> false XRegExp.searchLb("Catwoman's fluffy cat", "(?i)(?<=fluffy\\W+)", /cat/i); // -> 18 XRegExp.searchLb("Catwoman's fluffy cat", "(?i)(?<!fluffy\\W+)", /cat/i); // -> 0 XRegExp.matchAllLb("Catwoman's cats are fluffy cats", "(?i)(?<=fluffy\\W+)", /cat\w*/i); // -> ["cats"] XRegExp.matchAllLb("Catwoman's cats are fluffy cats", "(?i)(?<!fluffy\\W+)", /cat\w*/i); // -> ["Catwoman", "cats"] XRegExp.replaceLb("Catwoman's fluffy cat is a cat", "(?i)(?<=fluffy\\W+)", /cat/ig, "dog"); // -> "Catwoman's fluffy dog is a cat" XRegExp.replaceLb("Catwoman's fluffy cat is a cat", "(?i)(?<!fluffy\\W+)", /cat/ig, "dog"); // -> "dogwoman's fluffy cat is a dog" XRegExp.replaceLb("Catwoman's fluffy cat is a cat", "(?i)(?<!fluffy\\W+)", /cat/ig, function ($0) { var first = $0.charAt(0); return first === first.toUpperCase() ? "Dog" : "dog"; }); // -> "Dogwoman's fluffy cat is a dog"
Snadné hrachové lisování citronu. 🙂