JavaScript拆分字符串時產生空字符怎么解決
來源:易賢網 閱讀:831 次 日期:2014-10-15 15:21:11
溫馨提示:易賢網小編為您整理了“JavaScript拆分字符串時產生空字符怎么解決”,方便廣大網友查閱!

一、問題描述

使用JavaScript的split方法拆分字符串時出現一些空字符串"",尤其是當使用正則表達式作為分隔符的時候。

二、相關問題

javascript正則表達式對字符串分組時產生空字符串組?

在上面這個問題中,題主使用正則表達式對字符串進行分割時產生了多個空字符串"",代碼如下:

代碼如下:

'張sdf四上法asdf翁芬aa33網s'.split(/([u4e00-u9fa5]{1})/gi);

//輸出["", "張", "sdf", "四", "", "上", "", "法", "asdf", "翁", "", "芬", "aa33", "網", "s"]

那么,產生這些空字符串的原因是什么?

三、問題分析

在Google上搜索了一番,發現相關的結果并不多,即便有,詳細解釋的也不多,大概的說了一下,然后就給出了一個ECMAScript規范的鏈接??磥硪胫勒嬲脑颍椭荒苡仓^皮看規范了。

四、相關標準

那么,接下來,按照國際慣例,先上ECMAScript的標準鎮樓。

代碼如下:

String.prototype.split (separator, limit)

這個章節詳細介紹了split方法的執行步驟,如果感興趣的話可以一步一步的認真看完,我在這里只把和產生空字符串相關的步驟拿出來解釋一下,不當之處,歡迎大家提出。

五、相關步驟

摘取部分步驟:

整個過程中最主要的步驟是第13步這個循環,而這個循環主要做的事情如下:

定義p, q的值,每一次循環開始的時候p和q的值是相同的(該步驟在循環之外);

調用SplitMatch(S, q, R)這個方法對字符串進行拆分;

根據返回結果的不同,執行不同的分支,主要分支為分支ⅲ;

分支ⅲ又分成了8個小步用來將返回的結果填充到事先定義好的數組A中

在這個8小步中,步驟1的作用是返回原始字符串的一個子串,開始位置是p(包含在內),結束位置是q(不包含在內),注意:在這一步中會產生空字符串,我將其標記為截取字符串,方便下文引用。

將上一步的子串添加到數組A中

接下來的幾步是更新相關的變量,繼續下一次循環。(步驟7的作用是將正則表達式中的捕獲分組保存到數組A中,和產生空字符串無關)

SplitMatch(S, q, R)

接下來,我們需要了解一下SplitMatch(S, q, R)這個方法做了些什么事。這個方法在split規范中的下方有提及。它主要做的事是,根據分隔符(separator)的類型進行相應的操作:

如果分隔符是RegExp類型的,調用RegExp的內部方法[[Match]]來對字符串進行匹配,如果匹配失敗,返回failure,否則,返回一個MatchResult類型的結果。

如果分隔符是字符串,進行匹配判斷,失敗返回failure,成功返回MatchResult類型的結果。

MatchResult

上面的步驟中又引出了一個MatchResult類型的變量。通過查文檔發現,該類型的變量有兩個屬性endIndex和captures,endIndex的值是字符串匹配的位置加上1,captures可以理解為一個數組,當分隔符為正則表達式時,它里面的元素是分組捕獲的值;當分隔符為字符串時,它為一個空數組。

接下來

我們從上面的步驟可以看出,分割的字符串是在截取字符串這一步驟中產生的(正則表達式的分組捕獲除外)。它的作用是截取指定開始(包含在內)和結束位置(不包含在內)之間的字符串,那它什么時候會返回""呢?有一種特殊情況是開始位置和結束位置的值相等,這只是猜想而已,因為該規范沒有給出截取字符串的規范步驟。

都走到這里了,為什么不再往前走一步呢?

于是,我試著搜索了一些V8的源碼,看看能不能找到具體的實現方法。確實找到了相關的代碼,源碼鏈接

這里摘取其中一部分:

代碼如下:

function StringSplitJS(separator, limit) {

...

...

//分隔符是字符串的情況

if (!IS_REGEXP(separator)) {

var separator_string = TO_STRING_INLINE(separator);

if (limit === 0) return [];

// ECMA-262 says that if separator is undefined, the result should

// be an array of size 1 containing the entire string.

if (IS_UNDEFINED(separator)) return [subject];

var separator_length = separator_string.length;

//分隔符是空字符串,直接返回了字符數組

if (separator_length === 0) return %StringToArray(subject, limit);

var result = %StringSplit(subject, separator_string, limit);

return result;

}

if (limit === 0) return [];

// 分隔符是正則表達式的情況,調用StringSplitOnRegExp

return StringSplitOnRegExp(subject, separator, limit, length);

}

//此處省略若干代碼

我在代碼中發現,在填充數組的時候會調用%_SubString這個方法來截取字符串,可惜的是我沒有找到他的相關定義,如果有找到的同學歡迎告知。但是,我發現JavaScript中substring這個方法所對應的StringSubstring這個方法會調用%_SubString這個方法,并將其結果返回。那么如果'abc'.substring(1,1)返回"",則表明%_SubString這個方法在開始位置和結束位置相同的時候會返回"",結果大家一試便知。

那么,什么時候會出現開始位置等于結束位置(即q === p)的情況呢?我按照上面的步驟一步一步的進行分析,最終發現:

當原始字符串S匹配過一次分隔符之后,緊接著,字符串S的下一個位置還匹配分隔符。如:'abbbc'.split('b'),'abbbc'.split(/(b){1}/)

另一種情況是字符串開頭的一個或幾個字符匹配分隔符。如:'abc'.split('a'),'abc'.split(/ab/)

還有一種情況是字符串結尾的一個或幾個字符串匹配分隔符,與之相關的步驟是第14步。

如:'abc'.split('c'),'abc'.split(/bc/)

此外,當使用正則表達式作為分隔符的時候,返回的結果中還有可能出現undefined。

如:'abc'.split(/(d)*/)

回過頭來再看看開頭的那個例子,是不是滿足上面幾種情況?

六、題外話

這是我第一次這么仔細的看ECMAScript的標準規范,看的過程確實很痛苦,但明白之后就感覺很痛快了。也感謝題主提出的這個問題,以及追問。

順便提一句,正則表達式作為分隔符時,global修飾符g是會被忽略的,這也算是一次額外的收獲。

更多信息請查看IT技術專欄

更多信息請查看腳本欄目
由于各方面情況的不斷調整與變化,易賢網提供的所有考試信息和咨詢回復僅供參考,敬請考生以權威部門公布的正式信息和咨詢為準!

2026國考·省考課程試聽報名

  • 報班類型
  • 姓名
  • 手機號
  • 驗證碼
關于我們 | 聯系我們 | 人才招聘 | 網站聲明 | 網站幫助 | 非正式的簡要咨詢 | 簡要咨詢須知 | 新媒體/短視頻平臺 | 手機站點 | 投訴建議
工業和信息化部備案號:滇ICP備2023014141號-1 云南省教育廳備案號:云教ICP備0901021 滇公網安備53010202001879號 人力資源服務許可證:(云)人服證字(2023)第0102001523號
云南網警備案專用圖標
聯系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關注公眾號:hfpxwx
咨詢QQ:1093837350(9:00—18:00)版權所有:易賢網
云南網警報警專用圖標
未满十八18勿进黄网站免费看