はじめに
職場でPowerShellのコードを見ていたら正規表現を使った処理が幾つも出てきたのですが、その一部にあまり見慣れない書き方があったので記事としてまとめてみました。
学習環境
今回はVS Codeを使いました。
正規表現の基礎
- PowerShellには
match
とlike
、notmatch
とnotlike
という似た意味合いの演算子がありますが、それぞれ役割が違っています。
演算子名 | 意味 |
---|---|
-match | 文字列が正規表現パターンと一致 |
-notmatch | 文字列が正規表現パターンと不一致 |
-like | 文字列がワイルドカード(*)を含むパターンと一致 |
-notlike | 文字列がワイルドカード(*)を含むパターンと不一致 |
match/notmatch/like/notlikeの使い分け
$text = "2023-12-05"
Write-Host "match: $($text -match "^\d{4}-\d{2}-\d{2}$")"
Write-Host "notmatch: $($text -notmatch "^\d{4}-\d{2}-\d{2}$")"
Write-Host "like: $($text -like "2023-11*")"
Write-Host "notlike: $($text -notlike "2023-11*")"
実行結果
match: True
notmatch: False
like: False
notlike: True
グループ化コンストラクトとキャプチャ
- Microsoft Learnを見ると、キャプチャというものについて以下のように書かれていました。
グループ化コンストラクトは、キャプチャまたは無視できる部分文字列に入力文字列を分離します。
グループ化された部分文字列は、部分式と呼ばれます。
既定では、部分式は番号付きグループにキャプチャされますが、名前を割り当てることもできます。
- はっきりと説明が書かれていないので推測ですが、「グループ化コンストラクト」と「グループ化された部分文字列」「キャプチャ」はそれぞれ以下のような意味合いだと思われます。
用語 | 意味(推測ですが...) |
---|---|
グループ化コンストラクト | 正規表現中で半角丸カッコで囲まれた部分のこと。 |
グループ化された部分文字列 | 「グループ化コンストラクト」にマッチした部分文字列のこと。 |
キャプチャ | マッチした文字列を捕捉すること。 |
- またキャプチャされたテキストについては、以下のようにHashtable型の
$Matches
という変数に格納されるそうです。
キャプチャされたテキストを取得するには、
$Matches
Hashtable 自動変数を使用します。 一致全体を表すテキストは、キー 0に格納されます。
- 以下の「キャプチャの例(1)」を見ると、確かに
$Matches[0]
に「マッチした部分の全体」が入っていました。
キャプチャの例(1)
$text = "created_date: 2023-12-05 22:18:25"
$text -match "\d{4}-\d{2}-\d{2}"
$Matches
実行結果(1)
True
Name Value
---- -----
0 2023-12-05
- 次に「グループ化コンストラクト」を使ってみると、
$Matches[1]
以降にグループ化コンストラクトにマッチした部分が順に入っていました。- この書き方だと、Split関数を使ってゴリゴリ書くよりもスマートに感じます。
- 一方で、PowerShellに詳しくない人が
$Matches[1]
を見ても「年」を取り出しているとは想像しづらいと思うので、適切なコメントが必要なのではと感じました。
キャプチャの例(2)
$text = "created_date: 2023-12-05 22:18:25"
$text -match "(\d{4})-(\d{2})-(\d{2})"
$Matches
実行結果(2)
True
3 05
2 12
1 2023
0 2023-12-05
名前付きキャプチャ
- さらに、グループ化コンストラクトの先頭に
?<keyname>
を付けることで、$Matches
から番号(index)ではなく名称を指定してマッチした文字列を取得することができます。- これはとても便利な機能である反面、正規表現が長くなって読みづらくなると思うので、使いどころを選ぶように感じます...
キャプチャの例(3)
$text = "created_date: 2023-12-05 22:18:25"
$text -match "(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})"
$Matches
実行結果(3)
True
Name Value
---- -----
month 12
day 05
year 2023
0 2023-12-05