JavaScript >> Javascript 文檔 >  >> Tags >> regex

JavaScript 正則表達式 Lookbehind Redux

五年前,我發布了 在 JavaScript 中模仿 Lookbehind 在這個博客上,我詳細介紹了幾種在 JavaScript 中模擬正面和負面回溯的方法。那時我的方法都相當粗糙,並且要正確地自定義其中任何一個以使用給定的模式是很複雜的。此外,它們僅用於模擬基於正則表達式的替換中的後視。

為了更容易使用lookbehind,我最近在 GitHub 上發布了一組簡短的函數。他們使用 XRegExp v2,所以你也應該檢查一下。

代碼如下:

// 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));

壓縮和 gzip 壓縮後小於 0.5 KB。它提供了一組函數,可以輕鬆模擬領先的後視:

  • XRegExp.execLb
  • XRegExp.testLb
  • XRegExp.searchLb
  • XRegExp.matchAllLb
  • XRegExp.replaceLb

這些函數中的每一個都接受三個參數:要搜索的字符串、作為字符串的後向模式(可以使用 XRegExp 語法擴展)和主正則表達式。 XRegExp.replaceLb 接受第四個參數作為替換值,可以是字符串或函數。

用法示例如下:

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"

易榨檸檬汁。 🙂


Tutorial JavaScript 教程
  1. 改造,改造!第三部分:如何從 Wordpress 切換到 Jekyll

  2. 何時使用函數表達式與函數聲明

  3. 尋找最好的在線 JavaScript 學校

  4. Next.js 視口元標記不應在 _document.js 中使用

  5. 在 JavaScript 中設置請求標頭

  6. D3.js 中數據綁定的初學者指南

  7. 如何在html中顯示特定文本的超鏈接

  1. 內置角管道 - DecimalPipe - 第 3 部分

  2. 我是怎麼認識你的...刮刀的?

  3. 什麼是原生 JavaScript?

  4. 如何使用 React Router 改進 React 應用程序的用戶體驗

  5. 7 個您作為開發人員不會討厭的令人興奮的網站。

  6. 如何遞歸地使這個循環所有孩子?

  7. 使用 babel-plugin-macros 節省手動工作

  1. safari 和 chrome javascript 控制台多行

  2. Eclipse Neon.3 的 JBoss 工具和 Red Hat Developer Studio 維護版本

  3. Forest Cuties - 從牆上的海報到利用網絡貨幣化和 NFT 的手機遊戲

  4. 使用 lxml 和 pandas 在 Python 中進行 Web 抓取