理系公務員のプログラミング日記

【JS忍者】正規表現

タグ:
JavaScript

正規表現はしっかり理解せずになんと無く書いてた分野。 冒頭に「多くのWeb開発者が、正規表現を無視して幸せな人生を送っている」って書かれててワロタ

7.2 正規表現の概要

7.2.1 正規表現の説明

たとえば、"test"と完全に一致する正規表現は以下の2パターンで書ける。

const pattern_1 = /test/; const pattern_2 = new RegExp("test");

正規表現の内容がすでに開発の時点で判明している場合はリテラルの構文であるpattern_1を使う方が良い。 正規表現が実行時に、文字列の中に動的に構築される場合は、コンストラクタによるpattern_2の場合を使うのが良い。

7.2.2 項と演算子

文字

[abc]・・・"a"か"b"か"c"のどれかにマッチする。
[^abc]・・・"a"か"b"か"c"以外の文字とマッチする。
[a-m]・・・"a"〜"m"までのどれかにマッチする。
\ ・・・エスケープ文字。
/^test/・・・"test"が対象の先頭にあるとマッチする。
/test$/・・・"test"が対象の末尾にあるとマッチする。

繰り返し

A? ・・・Aが1個あっても無くてもマッチする。
A+ ・・・Aが1個以上あればマッチする。
A* ・・・Aが0個以上あればマッチする。
A{4} ・・・Aが4個あればマッチする。

定義済み文字クラス

\d ・・・任意の数字(decimal digit)。[0-9]と等価。
\w ・・・任意の単語文字(word)。[A-Za-z0-9_]と等価。
\s ・・・任意のUnicode空白文字。

7.3 正規表現のコンパイル

new RegExp()コンストラクタを使うと、動的に変化する正規表現を作成できる。 こうすることで、各パターンの場合の正規表現を書く必要がなくなり、性能が改善できる。

<div class="samurai ninja"></div> <div class="ninja samurai"></div> <div></div> <span class="samurai ninja ronin"></span> <script> function findClassInElements(className, type){ const elems = document.getElementByTagName(type || *); const regex = new RegExp("(^|\\s)" + className + "(\\s|$)"); const results = []; for ( let i = 0; i < elems.length; i++ ){ if ( regex.test(elems[i].className)){ results.push(elems[i]) } return results; } } findClassInElements("ninja","div").length == 2 // True findClassInElements("ninja","span").length == 1 // True findClassInElements("ninja").length == 3 // True </script>

7.4 マッチした部分をキャプチャする

マッチした部分だけでなく、その内部の数値などを別に取り出す機能としてキャプチャがある。

下記は不透明度を表すopacityからその数値をキャプチャとして取得する。

<div id="opacity" style="opacity:0.5; filter:alpha(opacity=50);"> </div> <script> function getOpacity(elem) { const filter = elem.style.filter; // filterプロパティが存在するか return filter ? // 不透明度文字列が存在しているか filter.indexOf("opacity=") >= 0 ? // /opacity=([^)]+)/ のうち ([^)]+) がキャプチャ。 // opacity=に続く)以外の文字 を全体マッチとは別に取り出す。 // キャプチャは全体マッチの次に配置されるので[1]で指定する。 (parseFloat(filter.match(/opacity=([^)]+)/)[1]) / 100) + "" : "" : elem.style.opacity; } getOpacity(document.getElementById("opacity")) >> "0.5" </script>

7.5 置換関数を使う

Stringオブジェクトのreplace()メソッドは、第一引数に正規表現を受け取ると、パターンにマッチした部分を置換する。 もしグローバル正規表現だった場合は複数の部分を一度に変換できる。 第二引数に利用できる関数を工夫することで、置き換え以外の方法にも利用することができる。

function compress(source){ // 見つかったkeyを保存する let keys = {}; console.log(source.match(/([^=&]+)=([^&]*)/)) // ["foo=1", "foo", "1", index: 0, input: "foo=1&foo=2&blah=a&blah=b&foo=3", groups: undefined] source.replace( /([^=&]+)=([^&]*)/g, // キーと値の情報を抽出する //グローバルサーチなので、マッチする度に[マッチしたテキスト全体、そのマッチにおけるキャプチャ群]の //可変調パラメータリストを関数に渡す function(full, key, value){ // 副作用 keys[key] = (keys[key] ? keys[key] + "," : "") + value; // 元の文字を置換えたいわけではないので、""を返す return ""; } ); let result = []; for (let key in keys){ result.push(key + "=" + keys[key]); } // & で結果を連結する return result.join("&"); } compress("foo=1&foo=2&blah=a&blah=b&foo=3") >> "foo=1,2,3 &blah = a,b"