Powershell入門 - 13.正規表現①

前回、テキストファイルやCSVファイルの操作方法について学びました。  
今回は、より高度な内容として**正規表現**を学びます。  

正規表現は、テキストの検索、置換などでよく用いられるものです。
慣れるまでは大変ですが、非常に便利なので、頑張って覚えていきましょう。

# 1. 正規表現の基礎

まず、自分の家の郵便番号を思い浮かべましょう。  
多くの方が「3桁の数字,ハイフン,4桁の数字」を思い浮かべたと思います。  

郵便番号、電話番号などの多くの番号は、その番号の記述パターンが決まっています。  
そのため、その記述パターンさえ分かれば、大量のテキストデータの中から、そのパターンに該当する文字列を瞬時に見つけ出すことも、計算機の力を使えば可能です。  

このパターンを記述するための記法が**正規表現**になります。

正規表現の使い方は大きく3種類あります。
1. パターンに該当する最初の1件の文字列のみ取得する
2. パターンに該当するすべての文字列を取得する
3. パターンに該当するすべての文字列を置換する

書き方がそれぞれ異なりますので、順番に見ていきましょう。

## 1.1. パターンに該当する最初の1件の文字列のみ取得する
正規表現を使った文字列の検索を行う場合、`-match演算子`を使います。  

```powershell
検索対象文字列 -match パターン文字列
```

例として、郵便番号の検索を行ってみたいと思います。  
`match`演算子の右側に書かれた文字列が郵便番号を表す正規表現になります。  
この読み方は後で説明しますので、今はこれが郵便番号を表しているということのみ理解しましょう。

```powershell
$s = Read-Host "郵便番号を入力してください"
$bln = $s -match "\d{3}-\d{4}"
Write-Host $bln
```

入力された文字列内に郵便番号のパターンに該当する文字列が含まれている場合True、そうでなければFalseが返ったと思います。  
このように、`-match演算子`の結果は「該当する文字列を含むかどうかの真理値(bool型)」になります。  

では、実際にパターンに該当した文字列を取得するにはどうすればよいでしょうか？
この場合、以下のようにすることで、文字列を取得できます。

```powershell
$s = Read-Host "郵便番号を入力してください"
$bln = $s -match "\d{3}-\d{4}"
Write-Host $bln
Write-Host $Matches[0]
```

`$Matches`変数は、Powershellであらかじめ用意された変数で、直前の-match演算の結果が格納されています。
`$Matches`にパターンに該当した文字列のリストが格納されているので、この0番目を取得することで該当文字列を取得できます。

#### 注意
-matchは「パターンに該当する最初の1件の文字列」のみ取得するため、検索対象文字列に郵便番号が複数含まれていた場合でも、`$Matches`リストのサイズが2や3に増えるわけではありません。
では、どのような時に2件目、3件目が入るかですが、こちらは別の機会に紹介します。

---

#### 例題1.
以下の文字列sから携帯番号を抜き出しなさい。  

携帯番号を表す正規表現は以下を使用すること  
'\d{3}-\d{4}-\d{4}'

```powershell
$s = "郵便番号：001-0001, 電話番号(自宅):0439-00-1234, 電話番号(携帯):080-0001-1234"
```

#### 例題2.
例題1の正規表現として与えられる文字列をよく観察し、例題1の文字列sから電話番号(自宅)を抜き出すにはどこをどう修正すべきか考え、抜き出した自宅の電話番号の文字列を表示しなさい。

---

## 1.2. パターンに該当するすべての文字列を取得する
パターンに該当する文字列を複数件取得したい場合、`Matchesメソッド`を使用します。  
1件のみ取得の場合と、書き方、使い方が大きく異なるので注意しましょう。

```powershell
[regex]::Matches(検索文字列, パターン文字列)
```

先ほどの`-match演算子`の結果は「該当する文字列を含むかどうかの真理値(bool型)」でした。  
`Matchesメソッド`ではどうでしょうか。
以下の結果を確認しましょう。

```powershell
$s = "名前: ああああ, 郵便番号：001-0001`n
名前:いいいい、郵便番号：001-0002`n
名前:うううう、郵便番号：001-0003`n"

$m = [regex]::Matches($s, "\d{3}-\d{4}")
$m
```
#### 出力結果
```powershell
Groups   : {0}
Success  : True
Name     : 0
Captures : {0}
Index    : 15
Length   : 8
Value    : 001-0001

Groups   : {0}
Success  : True
Name     : 0
Captures : {0}
Index    : 39
Length   : 8
Value    : 001-0002

Groups   : {0}
Success  : True
Name     : 0
Captures : {0}
Index    : 63
Length   : 8
Value    : 001-0003
```


結果を見ると分かりますが、`Matchesメソッド`の戻り値にはパターンに該当した結果に関するオブジェクトが格納されています。  
このオブジェクトのValue属性にマッチした文字列が格納されているので、文字列の取得は以下の通りに書けます。

```powershell
$s = "名前: ああああ, 郵便番号：001-0001
名前:いいいい、郵便番号：001-0002
名前:うううう、郵便番号：001-0003
"
$m = [regex]::Matches($s, "\d{3}-\d{4}")
$m.Value
```

--- 
#### 例題3.
以下の文字列の中から、携帯電話番号に合致する文字列をすべて取得し、1行ずつ表示しなさい。
```powershell
$moji = "314-1592-6535-89-7932-384-626-4338-3279-50-2-8841-9716-9399-37510-582-0974-9445-923-078164-0-62-86-208-9986-28-034-8253-4211-7067-982-14808"
```

#### 例題4.
例題3で取得した文字列が`$moji`変数の何文字目に書かれているか、検索結果のそれぞれの文字列について表示しなさい。  

**ヒント**
サンプルで示した`Mathesメソッド`の出力結果をよく観察すること

---

# 3. パターンに該当するすべての文字列を置換する
検索してマッチした文字列すべてを別の文字列に置換したい場合、`Replaceメソッド`を使用しましょう。

```powershell
[regex]::Replace(検索文字列, パターン文字列, 置換文字列)
```
`Matchesメソッド`と比べて、引数が1つ増えています。  
前二つの引数を使って`Matchesメソッド`と同じように該当文字列を取得し、その文字列を3つ目の引数の値で置き換えています。
では、こちらもサンプルを見てみましょう。

```powershell
$s = "名前: ああああ, 郵便番号：001-0001
名前:いいいい、郵便番号：001-0002
名前:うううう、郵便番号：001-0003"

$m = [regex]::Replace($s, "\d{3}-\d{4}", "[個人情報のため削除します]")
$m
$m.GetType()
```

`$m.GetType()`の結果が示す通り、`Replaceメソッド`の戻り値は文字列となります。　　
この点が`Matchesメソッド`と異なりますので注意しましょう。

---
#### 例題5.
以下の文字列に含まれる携帯電話の番号を、以下の文字列に置換し、結果を表示しなさい。    
XXX-XXXX-XXXX

```powershell
$s = "郵便番号：001-0001, 電話番号(自宅):0439-00-1234, 電話番号(携帯):080-0001-1234"
```
---

以上が、正規表現でよく使われる演算子、メソッドの紹介になります。　　
ですが、正規表現による処理を使いこなすための一番のキモは、上記のメソッドを使いこなすことではなく、「正規表現の文法を使いこなすこと」です。

そこで、次回はPowershellの内容からはみ出しますが、正規表現の文法について学んでいきます。

Prev : [12.ファイルの参照・更新](./fcc0f8c9ee0c47c68a72)
Next : [14.正規表現②](./dd96e60c65db0bb4d0db)

[目次へ戻る](./926b8053a031539437a3)