問題の説明
いくつかの空の文字列「」は、特にデリミターとして正規表現を使用する場合、JavaScriptの分割方法を使用して文字列を分割するときに表示されます。
関連する質問
JavaScriptの正規表現は、文字列をグループ化するときに空の文字列グループを生成しますか?
上記の質問では、質問者は正規表現を使用して文字列を分割し、複数の空の文字列 ""を生成しました。コードは次のとおりです。
コードコピーは次のとおりです。
'Zhang SDF 4つの方法ASDF wengf aa33net s'.split(/([/u4e00-/u9fa5] {1})/gi);
// output ["" ""、 "zhang"、 "sdf"、 "four"、 "up"、 "、" "、" law "、" asdf "、" weng "、" "" "" "、" fen "、" aa33 "、" net "、" s "]
それで、これらの空の文字列の理由は何ですか?
問題分析
Googleで検索した後、関連する結果はあまりないことがわかりました。たとえあっても、詳細な説明は多くありませんでした。私は大まかにそれを言ってから、ECMAScript仕様へのリンクを与えました。本当の理由を知りたいなら、弾丸を噛んで規範を見ることができるようです。
関連標準
次に、国際的な慣行によれば、最初にECMAScriptの標準的な町の建物に行きます。
コードコピーは次のとおりです。
string.prototype.split(セパレーター、制限)
この章では、分割方法の実行手順を詳細に紹介します。興味がある場合は、段階的に慎重に読むことができます。ここで空の文字列を生成することに関連する手順のみを説明します。不適切なポイントがある場合、誰もがそれらに言及することを歓迎します。
関連手順
抽出するための部分的な手順:
プロセス全体で最も重要なステップは13番目のサイクルであり、このサイクルが行う主なことは次のとおりです。
•pとqの値を定義します。 pとqの値は、各ループの先頭で同じです(この手順はループの外側にあります)。
•SplitMatch(S、Q、R)メソッドを呼び出して、文字列を分割します。
•返された結果に従って異なるブランチを実行し、メインブランチはブランチです。
•ブランチは、返された結果を事前定義された配列に埋めるために8つの小さなステップに分割されます。
•この8つの小さなステップでは、ステップ1の目的は、元の文字列のサブストリングを返すことです。開始位置はp(含まれています)、および末端位置はq(含まれています)です。注:このステップでは、空の文字列が生成され、以下の引用の利便性のために文字列を傍受するとマークしました。
•前のステップからアレイにサブストリングを追加します
•次のいくつかの手順は、関連する変数を更新し、次のループを続行することです。 (ステップ7の目的は、正規表現のグループ化をアレイAに保存することです。これは、空の文字列の生成とは関係ありません)
splitmatch(s、q、r)
次に、splitmatch(s、q、r)メソッドが何をするかを理解する必要があります。この方法は、分割仕様で以下に説明します。それが主に行うことは、分離器のタイプに従って対応する操作を実行することです。
•区切り文字がregexpのタイプの場合、文字列に一致するようにRegexpの内部方法[[一致]]を呼び出します。一致が失敗した場合、失敗を返します。それ以外の場合は、MatchResultの結果を返します。
•区切り文字が文字列である場合、一致判断が実行され、障害が返され、MatchResultタイプの結果が正常に返されます。
MatchResult
上記の手順では、タイプのmatchResultの変数が導入されています。ドキュメントを調べることにより、このタイプの変数には2つの属性がendIndexとキャプチャがあることがわかりました。 EndIndexの値は、文字列と1の1つの位置です。キャプチャは配列として理解できます。区切り文字が正規表現である場合、その内部の要素はグループによってキャプチャされた値です。区切り文字が文字列である場合、それは空の配列です。
次
上記の手順から、文字列を傍受する段階で分割文字列が生成されていることがわかります(正規表現のグループキャプチャを除く)。その機能は、指定された開始(含まれている)とエンド位置(含まれる)の間で文字列を傍受することです。仕様には文字列を傍受するための仕様手順が与えられないため、開始位置と終了位置の値が等しい特別なケースがあります。これは単なる推測です。
私たちは皆ここに来ました、一歩前進してみませんか?
そこで、V8ソースコードを検索して、特定の実装方法を見つけることができるかどうかを確認しようとしました。関連するコード、ソースコードリンクを見つけました
ここにそれらのいくつかがあります:
コードコピーは次のとおりです。
function stringsplitjs(セパレーター、制限){
...
...
//区切り文字は文字列です
if(!is_regexp(隔て)){
var separator_string = to_string_inline(separator);
if(limit === 0)return [];
// ECMA-262は、セパレーターが未定義の場合、結果は
//文字列全体を含むサイズ1の配列になります。
if(is_undefined(separator))return [subject];
var separator_length = separator_string.length;
//セパレーターは空の文字列で、文字配列を直接返します
if(separator_length === 0)return%stringToArray(subject、lime);
var result =%stringsplit(subject、separator_string、limit);
返品結果;
}
if(limit === 0)return [];
//区切り文字が正規表現である場合、stringsplitonregexpを呼び出します
ReturnsplitonRegexp(被験者、セパレーター、制限、長さ);
}
//ここではいくつかのコードが省略されています
コードで、配列に入力すると、文字列をインターセプトするために%_Substringメソッドが呼び出されることがわかりました。残念ながら、私はその関連する定義を見つけませんでした。それを見つけた学生がいたら、私に知らせてください。ただし、JavaScriptのサブストリングメソッドに対応するSringSubstringメソッドは、%_Substringメソッドを呼び出して結果を返すことがわかりました。次に、 'abc'.substring(1,1)が ""を返す場合、それは%_substringメソッドが ""を返すことを意味します。試してみることで結果を伝えることができます。
では、開始位置はいつ終了位置(q === p)に等しくなりますか?私は上記のステップを段階的にたどり、最終的に見つけました:
•元の文字列sが区切り文字に一致すると、その後すぐに、文字列sの次の位置も区切り文字と一致します。例: 'abbbc'.split(' b ')、' abbbc'.split(/(b){1}/)
•別のケースは、文字列の先頭にある1つまたは複数の文字がセパレーターと一致することです。例: 'abc'.split(' a ')、' abc'.split(/ab/)
•文字列の端にある1つまたは複数の文字列が区切り文字と一致する別のケースがあり、関連するステップはステップ14です。
例: 'abc'.split(' c ')、' abc'.split(/bc/)
さらに、正規表現を区切り文字として使用する場合、返された結果に未定義が表示される場合があります。
例: 'abc'.split(/(d)*/)
最初の例を見てみましょう。上記の状況を満たしていますか?
オフトピック
ECMAScriptの標準仕様を非常に注意深く読んだのはこれが初めてです。読書のプロセスは確かに非常に苦痛ですが、それを理解した後、私はとても幸せに感じます。この質問とフォローアップの質問をありがとう。
ちなみに、正規表現がセパレーターとして使用されると、グローバル修飾子Gは無視され、これも追加のゲインです。