JavaScript >> Javascript 文檔 >  >> Tags >> split

JavaScript 拆分錯誤:已修復!

String.prototype.split 方法非常方便,因此很遺憾,如果您使用正則表達式作為其分隔符,結果可能會在跨瀏覽器中大相徑庭,以至於您很可能只是在代碼中引入了錯誤(除非您確切地知道您正在使用什麼樣的數據並且能夠避免這些問題)。這是其他人就這些問題發洩的一個例子。以下是使用帶有 split 的正則表達式時跨瀏覽器的不一致 :

  • Internet Explorer 會從結果數組中排除幾乎所有空值(例如,當兩個分隔符在數據中相鄰出現時,或者當分隔符出現在數據的開頭或結尾時)。這對我來說沒有任何意義,因為 IE 在使用字符串作為分隔符時確實包含空值。
  • Internet Explorer 和 Safari 不會將捕獲括號的值拼接到返回的數組中(此功能對於簡單的解析器等很有用)
  • 火狐不拼接undefined 作為非參與捕獲組的結果將值放入返回的數組中。
  • Internet Explorer、Firefox 和 Safari 存在各種額外的邊緣情況錯誤,它們不遵循拆分規範(這實際上非常複雜)。

情況非常糟糕,我過去只是避免使用基於正則表達式的拆分。

現在結束。

以下腳本提供了 String.prototype.split 的快速、統一的跨瀏覽器實現 ,並嘗試精確遵循相關規範(ECMA-262 v3 §15.5.4.14,pp.103,104)。

我還創建了一個相當快速和骯髒的頁面,您可以在其中測試超過 50 次 JavaScript 的 split 使用的結果 方法,并快速將瀏覽器的結果與正確的實現進行比較。在測試頁面上,第三列中的粉紅色線條突出顯示來自原生 split 的錯誤結果 方法。最右邊的列顯示了以下腳本的結果。在我測試過的所有瀏覽器(IE 5.5 - 7、Firefox 2.0.0.4、Opera 9.21、Safari 3.0.1 beta 和 Swift 0.2)中都是綠色的。

在瀏覽器中運行測試 .

這是腳本:

/*!
 * Cross-Browser Split 1.1.1
 * Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
 * Available under the MIT License
 * ECMAScript compliant, uniform cross-browser split method
 */

/**
 * Splits a string into an array of strings using a regex or string separator. Matches of the
 * separator are not included in the result array. However, if `separator` is a regex that contains
 * capturing groups, backreferences are spliced into the result each time `separator` is matched.
 * Fixes browser bugs compared to the native `String.prototype.split` and can be used reliably
 * cross-browser.
 * @param {String} str String to split.
 * @param {RegExp|String} separator Regex or string to use for separating the string.
 * @param {Number} [limit] Maximum number of items to include in the result array.
 * @returns {Array} Array of substrings.
 * @example
 *
 * // Basic use
 * split('a b c d', ' ');
 * // -> ['a', 'b', 'c', 'd']
 *
 * // With limit
 * split('a b c d', ' ', 2);
 * // -> ['a', 'b']
 *
 * // Backreferences in result array
 * split('..word1 word2..', /([a-z]+)(\d+)/i);
 * // -> ['..', 'word', '1', ' ', 'word', '2', '..']
 */
var split;

// Avoid running twice; that would break the `nativeSplit` reference
split = split || function (undef) {

    var nativeSplit = String.prototype.split,
        compliantExecNpcg = /()??/.exec("")[1] === undef, // NPCG: nonparticipating capturing group
        self;

    self = function (str, separator, limit) {
        // If `separator` is not a regex, use `nativeSplit`
        if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
            return nativeSplit.call(str, separator, limit);
        }
        var output = [],
            flags = (separator.ignoreCase ? "i" : "") +
                    (separator.multiline  ? "m" : "") +
                    (separator.extended   ? "x" : "") + // Proposed for ES6
                    (separator.sticky     ? "y" : ""), // Firefox 3+
            lastLastIndex = 0,
            // Make `global` and avoid `lastIndex` issues by working with a copy
            separator = new RegExp(separator.source, flags + "g"),
            separator2, match, lastIndex, lastLength;
        str += ""; // Type-convert
        if (!compliantExecNpcg) {
            // Doesn't need flags gy, but they don't hurt
            separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
        }
        /* Values for `limit`, per the spec:
         * If undefined: 4294967295 // Math.pow(2, 32) - 1
         * If 0, Infinity, or NaN: 0
         * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
         * If negative number: 4294967296 - Math.floor(Math.abs(limit))
         * If other: Type-convert, then use the above rules
         */
        limit = limit === undef ?
            -1 >>> 0 : // Math.pow(2, 32) - 1
            limit >>> 0; // ToUint32(limit)
        while (match = separator.exec(str)) {
            // `separator.lastIndex` is not reliable cross-browser
            lastIndex = match.index + match[0].length;
            if (lastIndex > lastLastIndex) {
                output.push(str.slice(lastLastIndex, match.index));
                // Fix browsers whose `exec` methods don't consistently return `undefined` for
                // nonparticipating capturing groups
                if (!compliantExecNpcg && match.length > 1) {
                    match[0].replace(separator2, function () {
                        for (var i = 1; i < arguments.length - 2; i++) {
                            if (arguments[i] === undef) {
                                match[i] = undef;
                            }
                        }
                    });
                }
                if (match.length > 1 && match.index < str.length) {
                    Array.prototype.push.apply(output, match.slice(1));
                }
                lastLength = match[0].length;
                lastLastIndex = lastIndex;
                if (output.length >= limit) {
                    break;
                }
            }
            if (separator.lastIndex === match.index) {
                separator.lastIndex++; // Avoid an infinite loop
            }
        }
        if (lastLastIndex === str.length) {
            if (lastLength || !separator.test("")) {
                output.push("");
            }
        } else {
            output.push(str.slice(lastLastIndex));
        }
        return output.length > limit ? output.slice(0, limit) : output;
    };

    // For convenience
    String.prototype.split = function (separator, limit) {
        return self(this, separator, limit);
    };

    return self;

}();

下載它 .

如果您發現任何問題,請告訴我。謝謝!

更新: 該腳本已成為我的 XRegExp 庫 的一部分 ,其中包括許多其他 JavaScript 正則表達式跨瀏覽器兼容性修復。


Tutorial JavaScript 教程
  1. 如何使用單獨的 node_modules 為容器和主機創建 Dockerized Node 應用程序

  2. 在反應中從公共文件夾導入圖像

  3. 使用純 CSS 和無 JavaScript 的菜單/側邊欄切換功能。

  4. 單擊以轉到實時動畫中的下一個位置

  5. VueJS:滾動頂部組件

  6. 繪圖表

  7. 簡短的內置調用

  1. 加速你的 JavaScript,第 4 部分

  2. 更改 React 提及建議列表的位置

  3. 終點線

  4. 連接反應前端和節點後端的不同方式

  5. 角度 api 響應中的異步和等待

  6. Redux 與 MobX:哪個最適合您的項目?

  7. 我的作品集👨🏼‍💻

  1. 你應該知道的 FE 行話 - SSG、SSR、CSR、VDOM

  2. 介紹 Payload - 適用於 JavaScript 開發人員的 2021 年 Node + React Headless CMS

  3. iPhone / iPad的javascript滾動事件?

  4. JSON簡介