正規表現のJavaScriptのコードハイライトを実現する方法
5372 ワード
今日はJSのハイライトの配色を変えたいと思って、午後にこの正規表現を我慢しました.次の長老が成長したものは正則的な表現で、見たら怖がらないでください.
今、私たちはそれをゆっくり分析することができます.この正規表現をよく見ると、多くの正規表現が|で接続されていることがわかります.今、私たちはそれを|分割して、一つ一つ分析します.
これは2番目で、この正規表現は文字列を一致させるために使用されます.文字列は単一引用符と二重引用符で使用できるので、この2つのいずれかに一致します.ここでは、最後にこの文字を一致させる必要があるため、カッコで囲む必要があります(「一致を取得」の「取得」は名詞です).一致文字列の終わりには、文字列の開始文字、すなわち開始時の引用符の種類を後方参照3で一致させることができます.この正規表現全体の先頭から数えるとあなたは気づくでしょう外側のカッコは、正規表現全体の3番目に一致します.これが文字列の先頭と末尾の部分で、中間の部分は文字列がエスケープを含むことができるため、私たちは反スラッシュに遭遇するとすぐにその後ろの文字をスキップします.反スラッシュの後ろにはエスケープが含まれているからです.しかし、これはマッチングエスケープにすぎないので、マッチング非エスケープの式を演算|で接続します.それは[^\]です.しかし、これは反スラッシュではない任意の文字に一致し、改行を含めることができますが、JSの文字列は改行を書くことはできません.改行に一致しないように追加する必要があります接続に使用したか、接続に使用したかの優先度が非常に低いため、優先度を修正するには横にカッコを付ける必要があります.通常のカッコを使用すると一致を取得するために使用されるので、(?:)を使用して非取得一致を完了します.
これは3、4、5、6番目で、これらはいくつかのキーワードに一致するだけで、必要な色が異なるためグループ化されています.これは何も言うことはありません.スキップします.
これは7番目で、通常の変数名に一致する役割を果たします.変数名の文字が消費されなければ、後で数字に一致するものが変数名の数字マッチングに出力される可能性があります.だからこの一歩は必要です.変数名の色がデフォルトの色なので、取得しません.JSの命名規則によると、変数名は数字で始まることができないので、私たちは[^Wd]|$で1つの変数の先頭に一致します.後は、数字、アルファベット、下線、ドル記号を任意に一致させることができます.これで変数名が消費されます.
これは8番目で、数字にマッチしています.数字の表現は2種類あるので、別々に書きます.|の左に16進数の数字の書き方があります.右は普通の数字の書き方で、これは小数と科学のカウント法を含むことができます.小数と科学カウント法はいずれもオプションで存在するため,カッコを付け,疑問符を付けてオプションマッチングとした.
これは9番目で、正規表現に一致します.前に非取得マッチングがあり、非カッコの終了にマッチングします.カッコが存在する場合、斜め棒は正規表現ではなく除算記号を表す可能性があるからです.後に正規表現のマッチングがあり、文字列のマッチングと似ていますが、最後に[gim]*が1つ増えただけです.これは正規表現の3つのマッチングモードであり、正規表現の範疇にも属するので、マッチングして取得します.
最後に、上に一致していないすべての文字を一致させ、各文字に一致させなければなりません.HTMLのエスケープが必要だからですこれで、この長い正則は分析が終わった.次に、実装例を示します.
今日はこの文章を急いでいるので、このコードの最適化をする時間がありません.まだ小さな穴がたくさんあるはずですが、全体的な考え方はそうです.これにより、JSでも他の言語でも、コードのハイライトは直接正則的に一致することができます.
/(\/\/.*|\/\*[\S\s]+?\*\/)|((["'])(?:\\.|[^\\
])*?\3)|\b(break|continue|do|for|in|function|if|else|return|switch|this|throw|try|catch|finally|var|while|with|case|new|typeof|instance|delete|void)\b|\b(Object|Array|String|Number|Boolean|Function|RegExp|Date|Math|window|document|navigator|location)\b|\b(true|false)\b|\b(null|undefined|NaN)\b|(?:[^\W\d]|\$)[\$\w]*|(0[xX][0-9a-fA-F]+|\d+(?:\.\d+)?(?:[eE]\d+)?)|(?:[^\)\]\}]|^)(\/(?!\*)(?:\\.|[^\\\/
])+?\/[gim]*)|[\S\s]/g
今、私たちはそれをゆっくり分析することができます.この正規表現をよく見ると、多くの正規表現が|で接続されていることがわかります.今、私たちはそれを|分割して、一つ一つ分析します.
(\/\/.*|\/\*[\S\s]+?\*\/)
これは2番目で、この正規表現は文字列を一致させるために使用されます.文字列は単一引用符と二重引用符で使用できるので、この2つのいずれかに一致します.ここでは、最後にこの文字を一致させる必要があるため、カッコで囲む必要があります(「一致を取得」の「取得」は名詞です).一致文字列の終わりには、文字列の開始文字、すなわち開始時の引用符の種類を後方参照3で一致させることができます.この正規表現全体の先頭から数えるとあなたは気づくでしょう外側のカッコは、正規表現全体の3番目に一致します.これが文字列の先頭と末尾の部分で、中間の部分は文字列がエスケープを含むことができるため、私たちは反スラッシュに遭遇するとすぐにその後ろの文字をスキップします.反スラッシュの後ろにはエスケープが含まれているからです.しかし、これはマッチングエスケープにすぎないので、マッチング非エスケープの式を演算|で接続します.それは[^\]です.しかし、これは反スラッシュではない任意の文字に一致し、改行を含めることができますが、JSの文字列は改行を書くことはできません.改行に一致しないように追加する必要があります接続に使用したか、接続に使用したかの優先度が非常に低いため、優先度を修正するには横にカッコを付ける必要があります.通常のカッコを使用すると一致を取得するために使用されるので、(?:)を使用して非取得一致を完了します.
\b(break|continue|do|for|in|function|if|else|return|switch|this|throw|try|catch|finally|var|while|with|case|new|typeof|instance|delete|void)\b|\b(Object|Array|String|Number|Boolean|Function|RegExp|Date|Math|window|document|navigator|location)\b|\b(true|false)\b|\b(null|undefined|NaN)\b
これは3、4、5、6番目で、これらはいくつかのキーワードに一致するだけで、必要な色が異なるためグループ化されています.これは何も言うことはありません.スキップします.
(?:[^\W\d]|\$)[\$\w]*
これは7番目で、通常の変数名に一致する役割を果たします.変数名の文字が消費されなければ、後で数字に一致するものが変数名の数字マッチングに出力される可能性があります.だからこの一歩は必要です.変数名の色がデフォルトの色なので、取得しません.JSの命名規則によると、変数名は数字で始まることができないので、私たちは[^Wd]|$で1つの変数の先頭に一致します.後は、数字、アルファベット、下線、ドル記号を任意に一致させることができます.これで変数名が消費されます.
(0[xX][0-9a-fA-F]+|\d+(?:\.\d+)?(?:[eE]\d+)?)
これは8番目で、数字にマッチしています.数字の表現は2種類あるので、別々に書きます.|の左に16進数の数字の書き方があります.右は普通の数字の書き方で、これは小数と科学のカウント法を含むことができます.小数と科学カウント法はいずれもオプションで存在するため,カッコを付け,疑問符を付けてオプションマッチングとした.
(?:[^\)\]\}]|^)(\/(?!\*)(?:\\.|[^\\\/
])+?\/[gim]*)
これは9番目で、正規表現に一致します.前に非取得マッチングがあり、非カッコの終了にマッチングします.カッコが存在する場合、斜め棒は正規表現ではなく除算記号を表す可能性があるからです.後に正規表現のマッチングがあり、文字列のマッチングと似ていますが、最後に[gim]*が1つ増えただけです.これは正規表現の3つのマッチングモードであり、正規表現の範疇にも属するので、マッチングして取得します.
[\S\s]
最後に、上に一致していないすべての文字を一致させ、各文字に一致させなければなりません.HTMLのエスケープが必要だからですこれで、この長い正則は分析が終わった.次に、実装例を示します.
<br>//
<br>var code=document.getElementById("code").innerHTML;
<br>// ,
<br>code=code.replace(/\r
|[\r
]/g,"
").replace(/^\s+|\s+$/g,"");
<br>//
<br>code=code.replace(/(\/\/.*|\/\*[.\s]+?\*\/)|((["'])(?:\\.|[^\\
])*?\3)|\b(break|continue|do|for|in|function|if|else|return|switch|this|throw|try|catch|finally|var|while|with|case|new|typeof|instance|delete|void)\b|\b(Object|Array|String|Number|Boolean|Function|RegExp|Date|Math|window|document|navigator|location)\b|\b(true|false)\b|\b(null|undefined|NaN)\b|(?:[^\W\d]|\$)[\$\w]*|(0[xX][0-9a-fA-F]+|\d+(?:\.\d+)?(?:[eE]\d+)?)|(?:[^\)\]\}]|^)(\/(?!\*)(?:\\.|[^\\\/
])+?\/[gim]*)|[.\s]/g,function(){
<br> var a,l,i,s;
<br> a=arguments;
<br> //
<br> for(i=1;i<=9;i++)if(s=a[i]){
<br> s=htmlEncode(s);
<br> //
<br> switch(i){
<br> case 1://
<br> return s.fontcolor("#998877").italics();
<br> case 2:case 3://
<br> return s.fontcolor("#AA5544");
<br> case 4://
<br> return s.fontcolor("#333388");
<br> case 5://
<br> return s.fontcolor("#5555AA");
<br> case 6://
<br> return s.fontcolor("#DD6600");
<br> case 7://
<br> return s.fontcolor("#BB4433");
<br> case 8://
<br> return s.fontcolor("#CC3322");
<br> case 9://
<br> // ,
<br> // , ,
<br> return htmlEncode(a[0]).replace(s,s.fontcolor("#33AA33"));
<br> };
<br> };
<br> //
<br> return htmlEncode(a[0]);
<br>});
<p></p>
<p>// <br>document.write(code);</p>
<p>//HTML <br>function htmlEncode(e){<br> var i,s;<br> for(i in s={<br> "&":/&/g,""":/"/g,"'":/'/g,<br> "<":/</g,">":/>/g,"<br/>":/
/g,<br> " ":/ /g," ":/\t/g<br> })e=e.replace(s[i],i);<br> return e;<br>};<br>
今日はこの文章を急いでいるので、このコードの最適化をする時間がありません.まだ小さな穴がたくさんあるはずですが、全体的な考え方はそうです.これにより、JSでも他の言語でも、コードのハイライトは直接正則的に一致することができます.