nDmロール(1):正規表現のフラグ

前エントリーより、スクリプトに起こすために以下いろいろ奮闘。
まずは「#nDm」に反応する正規表現から。

「#nDm」に反応する正規表現

またまたやってまいりました正規表現。文字情報を扱う限り、逃れられない気がしますが。
マッチして欲しい条件は以下の通り。

  1. 頭に半角の#
  2. 続いて半角の数字。何桁でも。
  3. 半角の「D」または「d」。
  4. 半角の数字。何桁でも。

以上をすべてそなえた文字列です。これをふまえて正規表現にしてみると、

  1. 頭に半角の# → #
  2. 続いて半角の数字。何桁でも。 → [0-9]+ または \d+
  3. 半角の「D」または「d」。 → D|d
  4. 半角の数字。何桁でも。 →  [0-9]+ または \d+

参考は例によって例のごとく、すぐ使える!正規表現サンプル集より。
全部あわせると「#[0-9]+D|d[0-9]+」または「#\d+D|d\d+」って感じでしょうか。
不安があるのは2箇所。半角#と「または」の意味の「|」。特に「|」の方はDとdを()でくくった方がいい、のかな?


というわけで簡単なテスト。使用したのはいつものIRCLimeChatではなく、「サクラエディタ」。
すぐ使える!正規表現サンプル集」に、テキストエディタの表示に正規表現を利用する方法が紹介されていたので、これを参考にしました。
といっても新規に立ち上げたテキストエディタに適当に文字列を打ち込み、それに正規表現で検索をかけただけですが。
で、結果、「|」の方はDとdを()でくくった方がいいことが分かりました。
LimeChatでも同じ結果が出るかは分からないけど、参考までに。

「#nDm」内の『数字だけに』反応する正規表現

「#nDm」は取り出せた。次はnやmを取り出したい……わけですが。
シーンインした時に侵蝕率を計算するスクリプトでは、「#シーンイン+20」のように登場する半角数字は1回だけだったので、素直に「\d+」と書けば「20」だけ取り出してくれました。
でも今度は2つあります。どうしましょう?

「マッチ結果を利用した配列の生成」

ここで思い出したのが、match()でさんざん悩んだ時のこと。
たしか正規表現を()でくくれば、その正規表現にマッチした文字列をいくつでも拾ってくれるとか何とか。
というわけでこういうスクリプトを書いてみました。

	if (text.match(/#\d+(D|d)\d+/)) {
		
		//該当文字列を配列arrTextに格納
		var arrMatchedText = text.match(/#\d+(D|d)\d+/);

		//文字列からダイスの面数と個数を配列arrDiceに格納
		var arrDiceData = arrMatchedText[0].match(/(\d+)/);

		//テスト出力
		send(channel, 'arrMatchedText[0]=' + arrText[0]);
		send(channel, '[0]=' + arrDiceData[0]);
		send(channel, '[1]=' + arrDiceData[1]);
	}
}

で、結果↓

21:10 (ten-you) aaaaaaaaaaaaaaa#2D10aaaaaaaaaaaa
21:10 (ten-you) arrMatchedText[0]=#2D10
21:10 (ten-you) [0]=2
21:10 (ten-you) [1]=2

……なぜか arrDiceData[1]が arrDiceData[0]と同じ数字を拾ってしまいます。なぜに?


とりあえずリファレンスをあれこれひっくり返し、「これか?」と思ったのが正規表現RegExpのページ。match()のカッコ内のオブジェクトです。

RegExp

概要

パターンに従ったテキストにマッチする正規表現オブジェクトを生成します。

RegExp - JavaScript | MDN

ここに、正規表現に付けるフラグについての解説がありました。

flags
フラグは、次の値を任意の組み合わせで指定できます。:

g
グローバルなマッチ

RegExp - JavaScript | MDN

で、

正規表現が g フラグを含んでいる場合、マッチのすべてを含む 配列 (Array) を返します。

String.prototype.match() - JavaScript | MDN

らしいです。ということは

		var arrDiceData = arrMatchedText[0].match(/(\d+)/g);

と書けばうまくいくはず!


で、実行結果です↓

21:17 (ten-you) aaaaaaaaaaaaaaa#2D10aaaaaaaaaaaa
21:17 (ten-you) arrMatchedText[0]=#2D10
21:17 (ten-you) [0]=2
21:17 (ten-you) [1]=10

21:17 (ten-you) aaaaaaaaaaaaaaa#1D10aaaaaaaaaaaa
21:17 (ten-you) arrMatchedText[0]=#1D10
21:17 (ten-you) [0]=1
21:17 (ten-you) [1]=10

どちらも1行目が入力、2行目以降が出力です。
よーしよしよし。

おまけ

フラグの中にはg以外にこういうのもありました

i
大文字・小文字の無視

RegExp - JavaScript | MDN

これを利用して、スクリプトの該当行を以下のように書き換えてみました。

	if (text.match(/#\d+D\d+/i)) {
		
		//該当文字列を配列arrMatchedTextに格納
		var arrMatchedText = text.match(/#\d+D\d+/i);

結果は以下の通り↓

22:16 (ten-you) #3D10
22:16 (ten-you) arrMatchedText[0]=#3D10
22:16 (ten-you) [0]=3
22:16 (ten-you) [1]=10

22:16 (ten-you) #5d10
22:16 (ten-you) arrMatchedText[0]=#5d10
22:16 (ten-you) [0]=5
22:16 (ten-you) [1]=10

どちらも1行目が入力、2行目以降が出力です。
「D」でも「d」でも反応します。正規表現としてはこっちの方が見やすいかな?

まとめ

正規表現だけでえらい長さになってしまったので、一度ここでまとめ。

正規表現のテキスト
\d+
[0-9]+と同じ意味。数字のみ拾う。
「または」。「A|B」は「AまたはBが該当する」の意。
()
()内にマッチしたものを記憶し、配列に格納
正規表現のフラグ
  • /正規表現テキスト/g のような書き方をする

以下のようなフラグがある

グローバルなマッチ。match()ではg フラグを含んでいる場合、マッチのすべてを含む 配列 (Array) を返す
大文字・小文字の無視


……ダイス振るスクリプト書いてませんよ。ここまで。