本記事はFIXERが提供する「cloud.config Tech Blog」に掲載された「2 桁以上の数値を含む正規表現」を再編集したものです。
はじめに
正規表現は文字列のパターンマッチングにおいて強力なツールですが、正規表現に対する知識不足によって意図せず落とし穴にはまることがあります。
今回は、半角数字で2桁以上の数値を含む、範囲の正規表現について考えてみましょう。
まずは簡単な2題のクイズを確認します。
Quiz 1
:1~64の数値にマッチする正規表現はどれでしょうか? 以下の中から正しいものをすべて選んでください。 1. ^[1-64]$ 2. ^[1-9]|[1-5][0-9]|6[0-4]$ 3. ^([1-9]|[1-5][0-9]|6[0-4])$ 4. ^(\d|[1-6][0-4])$ 5. ^([1-9]|[1-6][0-4])$
Quiz 2: 0~255の数値にマッチする正規表現はどれでしょうか? 以下の中から正しいものをすべて選んでください。 1. ^[0-255]$ 2. ^0|[1-9][0-9]?|1[0-9][0-9]|2[0-4][0-9]|25[0-5]$ 3. ^(0|[1-9][0-9]?|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ 4. ^([0-9][0-9]?|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ 5. ^(0|[1-9]
\d{0,1}|1
\d{2}|2[0-4]
\d|25[0-5])$
これらの正規表現に関して、期待通りのパターンマッチングを実現する正規表現をすぐに判断できましたか?正規表現の微妙な違いが、マッチング結果に大きな影響を与えます。
それでは、解答とその理由を詳しく見ていきましょう。
※正規表現チェッカーを使用して、手元で正規表現とパターンマッチを確認しながら進めると理解しやすいです。
1~64を表す正規表現
1~64の数値を満たす正規表現は、Quiz 1の選択肢3のみです。
Quiz 1 1~64の半角数字にマッチする正規表現はどれでしょうか? 以下の中から正しいものをすべて選んでください。 1. ^[1-64]$ ❌ 不正解 2. ^[1-9]|[1-5][0-9]|6[0-4]$ ❌ 不正解 3. ^([1-9]|[1-5][0-9]|6[0-4])$ ✅ 正解 4. ^(
\d|[1-6][0-4])$ ❌ 不正解 5. ^([1-9]|[1-6][0-4])$ ❌ 不正解
これらの選択肢を評価する際に必要な正規表現の知識を下記にまとめます。
▼表1:正規表現解説表 1
正規表現 | 意味 |
^ | 行頭一致 |
$ | 行末一致 |
- | 範囲 ※ただし、[]内で使用された場合 |
[1-9] | 1~9の半角数字に一致 |
[1-36] | 1~3と6の半角数字に一致 |
\d | 0~9の半角数字に一致 |
| | OR条件 |
() | グループ化 |
では、この表を踏まえて、それぞれの選択肢について詳しく見ていきましょう。
選択肢1 ^[1-64]$ は ❌ 不正解 です。
この表現は「1~6と4の半角数字1文字」にマッチします。正規表現の文字クラス [...] 内では、ハイフンは範囲を表しますが、[1-64] は「1~6と4の半角数字1文字」という意味になります。[1-64] では、1~64の半角数字という意味にはならないので注意が必要です。
これは実質的に [1234564] と同じで、「1, 2, 3, 4, 5, 6, 4」のいずれか1文字にマッチします。
つまり、「1~6の半角数字1文字」のみにマッチするため、13や64にマッチしないため不正解となります。
選択肢2: ^[1-9]|[1-5][0-9]|6[0-4]$ は ❌ 不正解 です。
この表現はグループ化が適切に行われていないため、以下のように解釈されます:
^[1-9]: 行頭が1~9の半角数字1文字
[1-5][0-9]: 行内の任意の場所に10~59の半角数字が存在する
6[0-4]$: 行末が60~64の半角数字
そのため、例えば「1abc」や「abc12」などの文字列にもマッチしてしまいます。
選択肢3: ^([1-9]|[1-5][0-9]|6[0-4])$ は ✅ 正解 です。 この表現は1~64の半角数字にマッチします: [1-9]: 1~9 の半角数字1桁の数字 [1-5][0-9]: 10~59の2桁の半角数字 6[0-4]: 60~64の2桁の半角数字 そして、これらの選択肢を |(OR)で連結し、全体を括弧でグループ化して、文字列の先頭(^)と末尾($)にアンカーを付けています。 つまり、^[1-9]$|^[1-5][0-9]$|^6[0-4]$ と同義ですね。
選択肢4: ^(
\d|[1-6][0-4])$ は ❌ 不正解 です。 この表現は以下のようにマッチします:
\d: 任意の1桁の半角数字(0~9) [1-6][0-4]: 1~6の数字の後に0~4の半角数字が続く これでは0にマッチしてしまい、また「36」や「59」などの半角数字とマッチしない表現になってしまいます。
選択肢5: ^([1-9]|[1-6][0-4])$ は ❌ 不正解 です。
この表現も選択肢4と同様の問題があります:
[1-9]: 1~9の半角数字1桁の数字
[1-6][0-4]: 1~6の数字の後に0~4の半角数字が続く
このような条件では、「15」や「28」、「36」や「59」などの半角数字とマッチしない表現になってしまいます。
これらのことから、選択肢3が唯一、1~64の半角数字のみにマッチする正規表現であることが確認できました。
0~255を表す正規表現
0~255の数値を満たす正規表現は、Quiz 2の選択肢3と5のみです。
Quiz 2 0~255の数値にマッチする正規表現はどれでしょうか? 以下の中から正しいものをすべて選んでください。 1. ^[0-255]$ ❌ 不正解 2. ^0|[1-9][0-9]?|1[0-9][0-9]|2[0-4][0-9]|25[0-5]$ ❌ 不正解 3. ^(0|[1-9][0-9]?|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ✅ 正解 4. ^([0-9][0-9]?|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ❌ 不正解 5. ^(0|[1-9]
\d{0,1}|1
\d{2}|2[0-4]
\d|25[0-5])$ ✅ 正解
これらの選択肢を評価する際に必要な正規表現の知識を下記にまとめます。
※確認しやすくするために、表 1と重複した内容も表記しています。
▼表2 正規表現解説表 2
正規表現 | 意味 |
^ | 行頭一致 |
$ | 行末一致 |
- | 範囲 ※ただし、[]内で使用された場合 |
[1-9] | 1~9の半角数字に一致 |
[1-36] | 1~3と6の半角数字に一致 |
\d | 0~9の半角数字に一致 |
| | OR条件 |
() | グループ化 |
? | 直前の文字を0または1回使用する |
{n} | 直前の文字またはパターンをn回繰り返す |
{m,n} | 直前の文字またはパターンをm回以上、n回以下繰り返す |
では、この表を踏まえて、それぞれの選択肢について詳しく見ていきましょう。
選択肢1: ^[0-255]$ は ❌ 不正解 です。
この表現は「0~2と5と5の半角数字1文字」にマッチします。
正規表現の文字クラス [...] 内では、ハイフンは範囲を表しますが、[0-255] は「0~2と5と5の半角数字1文字」という意味になります。[0-255] では、0~255の半角数字という意味にはならないので注意が必要です。 これは実質的に [01255] と同じで、「0, 1, 2, 5, 5」のいずれか1文字にマッチします。 つまり、「0~2の半角数字1文字」のみにマッチするため、149や213にマッチしないため不正解となります。
選択肢2: ^0|[1-9][0-9]?|1[0-9][0-9]|2[0-4][0-9]|25[0-5]$ は ❌ 不正解 です。
この表現はグループ化が適切に行われていないため、以下のように解釈されます:
^0: 行頭が0 [1-9][0-9]?: 行内の任意の場所に1~99の半角数字が存在する
1[0-9][0-9]: 行内の任意の場所に100~199の半角数字が存在する
2[0-4][0-9]: 行内の任意の場所に200~249の半角数字が存在する
25[0-5]$: 行末が250~255の半角数字
そのため、例えば「0abc」や「abc123」などの文字列にもマッチしてしまいます。
選択肢3: ^(0|[1-9][0-9]?|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ は ✅ 正解 です。
この表現は正しく 0~255の半角数字にマッチします:
0: 数字の 0
[1-9][0-9]?: 1~99の1桁または2桁の半角数字(先頭が0でない)
1[0-9]{2}: 100~199の3桁の半角数字(1の後に任意の半角数字が2つ)
2[0-4][0-9]: 200~249の3桁の半角数字
25[0-5]: 250~255の3桁の半角数字
そして、これらの選択肢を |(OR)で連結し、全体を括弧でグループ化して、文字列の先頭(^)と末尾($)にアンカーを付けています。
つまり、^0$|^[1-9][0-9]?$|^1[0-9]{2}$|^2[0-4][0-9]$|^25[0-5]$と同義ですね。
選択肢4: ^([0-9][0-9]?|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ は ❌ 不正解 です。
この表現は以下のようにマッチします:
[0-9][0-9]?: 0~99の1桁または2桁の半角数字
1[0-9]{2}: 100~199の3桁の半角数字
2[0-4][0-9]: 200~249の3桁の半角数字
25[0-5]: 250~255の3桁の半角数字
一見正しそうですが、`[0-9][0-9]?`の表現では「01」や「09」のような先頭に0がついた2桁の半角数字にもマッチしてしまいます。通常、数値として扱う場合は先頭の0は無視されるべきです。
選択肢5: ^(0|[1-9]
\d{0,1}|1
\d{2}|2[0-4]
\d|25[0-5])$ は ✅ 正解 です。 この表現も正しく 0~255の数字にマッチします: 0: 数字の0 [1-9]
\d{0,1}: 1~99の1桁または2桁の半角数字(先頭が0でない)
\dは任意の半角数字(0~9)を表す {0,1} は直前のパターンが0回または1回出現することを意味する 1
\d{2}:100~199の3桁の半角数字 2[0-4]
\d: 200~249の3桁の半角数字 25[0-5]: 250~255の3桁の半角数字 選択肢3と同様に、これらの選択肢を適切にグループ化し、アンカーを付けています。
\d{0,1} は
\d?と書くこともできます。
これらのことから、選択肢3と5が、0~255の半角数字のみにマッチする正規表現であることが確認できました。
まとめ
正規表現は適切に使用する場合に限り便利な機能であり、非常に柔軟で強力ですが、その柔軟性ゆえに思わぬバグを生み出すこともあります。特に複雑なパターンを扱う場合は、十分なテストを行い、エッジケースでも期待通りの動作をするか確認することが重要です。
正規表現を最大限に活用するためには、基本的な構文や特殊文字の意味、そして一般的なパターンについての知識が必要であると感じました。基本を理解し、実践を重ねることで、より効果的に活用できるようになりたいですね。
中島悠太/FIXER
2023年度新卒で入社。エンジニア1年生。
社内での担当はまだ未定。
社外では42Tokyoという場所でエンジニアとしてのスキルを研鑽しています。


この連載の記事
-
TECH
zshの初期設定がダサい…。表示内容を自分好みにカスタマイズしていく -
TECH
え、高級言語しか触ったことないのにCPUを自作するんですか!? -
TECH
Github Copilotで、コミットメッセージもAIに考えてもらう方法 -
TECH
Github Copilot Chatをさらに便利にする3つの機能 -
TECH
はじめてのOSSコントリビュートで“推しからのリプ”をもらった話 -
TECH
Kubernetesのcert-managerについて簡潔にまとめておきますね -
TECH
WSL2でのGitHubの認証をできる限り簡単に行う方法 -
TECH
MacでGitHub CLIの認証を行う方法 -
TECH
ゆるく理解する自作シェル実装1:そもそもシェルってどんなもの? -
TECH
プロンプトエンジニアリングのコツは「5W1Hを忘れずに」 -
TECH
GitHubの 超・超・超 基本的な使い方まとめ - この連載の一覧へ