ミッション形式で覚える文字列置換・正規表現超入門

# はじめに
この記事は私が自社社員向けに実施した「文字列置換・正規表現ハンズオン」の内容をまとめたものになります。
内容としてはVSCodeの操作に慣れていない人も含まれていたので、かなり簡単なレベルも含まれておりますがご了承ください。

## ファイル変換の必要性

エンジニアとして活動していると、「ファイル変換」の必要性に嫌でも出会います。
ある日突然「データベース内のデータを顧客が見やすいようにまとめる」という必要が生じるかもしれませんし、逆に「顧客のデータを適当に整形してデータベースに格納する」というオペレーションが必要になったりもするでしょう。
そういった際に文字列置換のテクニックと正規表現について覚えておいて損はありません。

正規表現は初学者にはとっつきにくいですが、使えるようになると非常に便利です。
ここではミッション形式で文字列置換、正規表現の練習をやってみましょう。

エディタは基本何でも良いですが、当記事ではVSCodeを念頭に置いています。
また、正規表現の知識0でクリアするのは不可能なので、ミッションに即して適宜こちらのサイトを参考にして良いものとします。
[正規表現チェッカー](https://weblabo.oscasierra.net/tools/regex/)
今は上記のサイトの意味が分からないかもしれませんが、追々理解できるようになるのでご安心ください。

## 平家物語を雅に読みやすくする
「読みやすくする」ことは大事です。プログラムであっても、社内ドキュメントとしても大事です。
さて、唐突ですがここに**平家物語**があります。

```
引用元：https://www.koten.net/heike/gen/001/
`祇園精舎の鐘の声諸行無常の響あり `娑羅双樹の花の色盛者必衰の理を顕す `奢れる人も久しからずただ春の夜の夢の如し `猛き者もつひには滅びぬ偏に風の前の塵に同じ
`遠く異朝を訪へば秦の趙高漢の王莽梁の周伊唐の禄山これらは皆旧主先皇の政にも従はず楽しみを極め諫めをも思ひ入れず天下の乱れん事を悟らずして民間の憂ふる所を知らざりしかば久しからずして亡じにし者共なり `近く本朝を窺ふに承平の将門天慶の純友康和の義親平治の信頼これらは猛き心も奢れる事も皆とりどりにこそありしか間近くは六波羅の入道前太政大臣平朝臣清盛公と申し人の有様伝へ承るこそ心も詞も及ばれね
`その先祖を尋ぬれば桓武天皇第五の皇子一品式部卿葛原親王九代の後胤讃岐守正盛が孫刑部卿忠盛朝臣の嫡男なり `かの親王の御子高視王無官無位にして失せ給ひぬ `その御子高望王の時初めて平の姓を賜はつて上総介に成り給ひしより忽ちに王氏を出でて人臣に列なる `その子鎮守府将軍義茂後には国香と改む `国香より正盛に至るまで六代は諸国の受領たりしかども殿上の仙籍をば未だ許されず
```
上記文章は1行目にある通り、[日本古典文学摘集](https://www.koten.net/) 様より引用させていただいたテキストです。
しかし見ての通り、ただサイトにある文章を何も考えずに貼り付けただけでは非常に読みにくいですね。

幸運なことに、見たところ文章と文章は" `"(半角スペースとバッククオート)で区切られているようです。

### ミッション1 改行
まずは" `"で改行してみましょう。

【解答】

```
引用元：https://www.koten.net/heike/gen/001/
`祇園精舎の鐘の声諸行無常の響あり
娑羅双樹の花の色盛者必衰の理を顕す
奢れる人も久しからずただ春の夜の夢の如し
猛き者もつひには滅びぬ偏に風の前の塵に同じ
`遠く異朝を訪へば秦の趙高漢の王莽梁の周伊唐の禄山これらは皆旧主先皇の政にも従はず楽しみを極め諫めをも思ひ入れず天下の乱れん事を悟らずして民間の憂ふる所を知らざりしかば久しからずして亡じにし者共なり
近く本朝を窺ふに承平の将門天慶の純友康和の義親平治の信頼これらは猛き心も奢れる事も皆とりどりにこそありしか間近くは六波羅の入道前太政大臣平朝臣清盛公と申し人の有様伝へ承るこそ心も詞も及ばれね
`その先祖を尋ぬれば桓武天皇第五の皇子一品式部卿葛原親王九代の後胤讃岐守正盛が孫刑部卿忠盛朝臣の嫡男なり
かの親王の御子高視王無官無位にして失せ給ひぬ
その御子高望王の時初めて平の姓を賜はつて上総介に成り給ひしより忽ちに王氏を出でて人臣に列なる
その子鎮守府将軍義茂後には国香と改む
国香より正盛に至るまで六代は諸国の受領たりしかども殿上の仙籍をば未だ許されず
```
これだけでも相当読みやすくなりましたね。

【方法】
VSCode(mac)の場合、cmd + option + fで置換パレットが開くので、画像のように入力して、下のフォーム右側の「全て置換」ボタンを押すだけです。
bをcに変換しようとしているボタンが「置換」ボタンで、abをacに変換しようとしているボタンが「全て置換」ボタンです。
![スクリーンショット 2021-02-17 13.30.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247157/452818be-0ef2-5829-f441-66a75c1cd944.png)
この際、上のフォーム右側の四角とアスタリスクが入ったマークをクリックしておく必要があります。
このマークこそまさに「正規表現を使用する」ボタンです。

正規表現は「文字列内で文字の組み合わせを照合するために用いられるパターン」[^1]とされていますが、わかりにくいですよね。
要するに、**「単純な文字では表現できない組み合わせや改行等を検索するための手段」**と捉えると良いと思います。

さて、そこで話が戻りますが、改行は正規表現で `\n` (バックスペース + n)で表現されます。[^2]

「正規表現を使用する」ボタンにチェックが入っているので、" \`" は `\n` という文字に変換されず、正しく改行に変換される、というわけです。

[^1]: [正規表現](https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Regular_Expressions)
[^2]: 改行の話をするとかなり奥深いのですが、便宜上ここではこのような説明のみとさせて頂きます。

### ミッション2 削除
```
引用元：https://www.koten.net/heike/gen/001/
`祇園精舎の鐘の声諸行無常の響あり
娑羅双樹の花の色盛者必衰の理を顕す
奢れる人も久しからずただ春の夜の夢の如し
猛き者もつひには滅びぬ偏に風の前の塵に同じ
`遠く異朝を訪へば秦の趙高漢の王莽梁の周伊唐の禄山これらは皆旧主先皇の政にも従はず楽しみを極め諫めをも思ひ入れず天下の乱れん事を悟らずして民間の憂ふる所を知らざりしかば久しからずして亡じにし者共なり
近く本朝を窺ふに承平の将門天慶の純友康和の義親平治の信頼これらは猛き心も奢れる事も皆とりどりにこそありしか間近くは六波羅の入道前太政大臣平朝臣清盛公と申し人の有様伝へ承るこそ心も詞も及ばれね
`その先祖を尋ぬれば桓武天皇第五の皇子一品式部卿葛原親王九代の後胤讃岐守正盛が孫刑部卿忠盛朝臣の嫡男なり
かの親王の御子高視王無官無位にして失せ給ひぬ
その御子高望王の時初めて平の姓を賜はつて上総介に成り給ひしより忽ちに王氏を出でて人臣に列なる
その子鎮守府将軍義茂後には国香と改む
国香より正盛に至るまで六代は諸国の受領たりしかども殿上の仙籍をば未だ許されず
```
よく見ると、文章先頭に`` ` ``が混じっちゃってますね。
次はこれを削除しましょう。

注意点として、「文章先頭の」`` ` `` だけを削除するようにしてください。もしかすると平家物語はどこかに`` ` `` (バックスペース)を含んでいるかもしれません。……とりあえずそういうことにしておいてください。

また、せっかくなので箇条書きにしてみましょう。
全行の先頭に`・`を付けてみてください。
……多少平家物語への冒涜な気がしてきましたが……

【解答】

```
・引用元：https://www.koten.net/heike/gen/001/
・祇園精舎の鐘の声諸行無常の響あり
・娑羅双樹の花の色盛者必衰の理を顕す
・奢れる人も久しからずただ春の夜の夢の如し
・猛き者もつひには滅びぬ偏に風の前の塵に同じ
・遠く異朝を訪へば秦の趙高漢の王莽梁の周伊唐の禄山これらは皆旧主先皇の政にも従はず楽しみを極め諫めをも思ひ入れず天下の乱れん事を悟らずして民間の憂ふる所を知らざりしかば久しからずして亡じにし者共なり
・近く本朝を窺ふに承平の将門天慶の純友康和の義親平治の信頼これらは猛き心も奢れる事も皆とりどりにこそありしか間近くは六波羅の入道前太政大臣平朝臣清盛公と申し人の有様伝へ承るこそ心も詞も及ばれね
・その先祖を尋ぬれば桓武天皇第五の皇子一品式部卿葛原親王九代の後胤讃岐守正盛が孫刑部卿忠盛朝臣の嫡男なり
・かの親王の御子高視王無官無位にして失せ給ひぬ
・その御子高望王の時初めて平の姓を賜はつて上総介に成り給ひしより忽ちに王氏を出でて人臣に列なる
・その子鎮守府将軍義茂後には国香と改む
・国香より正盛に至るまで六代は諸国の受領たりしかども殿上の仙籍をば未だ許されず
```

【方法】
``^` ``を` `に変換します。
![スクリーンショット 2021-02-24 11.59.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247157/d16dcd5a-181b-589c-f4d5-1bba391b1b8e.png)
`^`は正規表現で文章の先頭を意味します。
` `に変換する、というとパッと見意味不明かもしれませんが……
要は「無」に変換するということです。(半角スペースではないです)
「置換」欄を空にして、置換を実行しましょう。

その後、`^`を`・`に置換すると、解答のファイルが完成します。

また、「文章の先頭」は`^`でしたが、文末は`$`です。合わせて覚えましょう。

### ミッション3 パターンを見つける
さて、こうなってくると1行目の引用元表記が不自然に浮いてますね。
引用元はこちらの記事内でもう提示しているので、こちらのファイルからは削除してしまいましょう。

もちろん、1行目を手動で削除すれば1秒で済みます。
ですが、仮にこれが10万行のファイルで、しかもURLを含む文字列が複数行ある場合は……？

正規表現を使うしかありませんね。

「URLを含む行を全て削除する」は少しややこしいので、**「英語を含む行を全て削除する」**という問題にチャレンジしてみてください。英語は半角小文字のみ存在するものとします。

【解答】

```
・祇園精舎の鐘の声諸行無常の響あり
・娑羅双樹の花の色盛者必衰の理を顕す
・奢れる人も久しからずただ春の夜の夢の如し
・猛き者もつひには滅びぬ偏に風の前の塵に同じ
・遠く異朝を訪へば秦の趙高漢の王莽梁の周伊唐の禄山これらは皆旧主先皇の政にも従はず楽しみを極め諫めをも思ひ入れず天下の乱れん事を悟らずして民間の憂ふる所を知らざりしかば久しからずして亡じにし者共なり
・近く本朝を窺ふに承平の将門天慶の純友康和の義親平治の信頼これらは猛き心も奢れる事も皆とりどりにこそありしか間近くは六波羅の入道前太政大臣平朝臣清盛公と申し人の有様伝へ承るこそ心も詞も及ばれね
・その先祖を尋ぬれば桓武天皇第五の皇子一品式部卿葛原親王九代の後胤讃岐守正盛が孫刑部卿忠盛朝臣の嫡男なり
・かの親王の御子高視王無官無位にして失せ給ひぬ
・その御子高望王の時初めて平の姓を賜はつて上総介に成り給ひしより忽ちに王氏を出でて人臣に列なる
・その子鎮守府将軍義茂後には国香と改む
・国香より正盛に至るまで六代は諸国の受領たりしかども殿上の仙籍をば未だ許されず
```

【方法】
正直、ここからようやく本格的な正規表現に入るのですが、同時に急に難しくなります。
まず「なんらかの英語」は
`[a-z]`
で表されます。
英語が含まれる行は、**「任意の文字が0回以上繰り返された後、英語の文字に突き当たり、その後、任意の文字を0回以上繰り返し、改行に至る」**パターンとして表現できます。

「任意の1文字」は
`.`
で表され、「0回以上の繰り返し」は
`*`
で表されます。

最終的にそれを正規表現で表すと、
`.*[a-z].*\n`
となります。
つまり、`.*[a-z].*\n`を""に変換してあげると、英語を含む行が削除できます。
ただ、こちらの方法では最終行が該当行である場合ヒットしなくなるので、`.*[a-z].*$`を`\n`に変換するほうがより良いです。[^3]

### 応用ミッション 百人一首ウルトラソウル
[もしも百人一首の下の句が全てウルトラソウルだったら+その他](https://togetter.com/li/157346)

……。
よし、作ってみましょう。

```解答.txt
秋の田のかりほの盧のとまをあらみ　そして輝く ウルトラソウル
春過て夏来にけらし白妙の　そして輝く ウルトラソウル
……
百敷やふるき軒端の忍ふにも　そして輝く ウルトラソウル
```

参考として、百人一首を掲載してくれているサイトがこちらにあります。
[小倉百人一首 カルタ本文](http://www.asahi-net.or.jp/~sg2h-ymst/yamatouta/sennin/100i/100i_t.html)

```
天智天皇
001 秋の田のかりほの盧のとまをあらみ　我ころも手は露にぬれつゝ

持統天皇
002 春過て夏来にけらし白妙の　衣ほすてふあまの香来山

……(筆者による省略)

順徳院
100 百敷やふるき軒端の忍ふにも　なを餘りあるむかし成けり
```

こちらを解答.txtの形に変換してみましょう。

【方法】
まず、全ての句の先頭に番号が振られていますね。
こちらを削除しましょう。

「数字三回の繰り返しと半角スペース」です。
つまり、`[0-9]{3} `を削除します。({3}の直後に半角スペースがあります)

すると、こうなります。

```
天智天皇
秋の田のかりほの盧のとまをあらみ　我ころも手は露にぬれつゝ

持統天皇
春過て夏来にけらし白妙の　衣ほすてふあまの香来山

……

順徳院
百敷やふるき軒端の忍ふにも　なを餘りあるむかし成けり
```

次に、句と次の作者までの改行を消すため、「2連続の改行」を削除し、改行をひとつにします。
これは簡単ですね。
`\n\n`を`\n`に変換しましょう。

```
天智天皇
秋の田のかりほの盧のとまをあらみ　我ころも手は露にぬれつゝ
持統天皇
春過て夏来にけらし白妙の　衣ほすてふあまの香来山
……
順徳院
百敷やふるき軒端の忍ふにも　なを餘りあるむかし成けり
```

次に、作者の行を消し、句の行だけを残しましょう。
これはとても難しいです。

句の行には全角スペースが含まれています。
つまり、作者の行は
**「全角スペースを含まない」**
行です。

**「文章の先頭から、全角スペースを除くなんらかの任意の1文字を繰り返し、改行に至る」までの行**が、消すべき行となります。
正規表現で`^`は、否定の意味もあります。

これらを統合すると、
`^[^　]+\n`
という正規表現が得られます。これを削除します。

```
秋の田のかりほの盧のとまをあらみ　我ころも手は露にぬれつゝ
春過て夏来にけらし白妙の　衣ほすてふあまの香来山
……
百敷やふるき軒端の忍ふにも　なを餘りあるむかし成けり
```

最後に、下の句をウルトラソウルにしましょう。
**「全角スペースの後に続く任意の1文字の繰り返し」**を「そして輝く ウルトラソウル」に変換します。

正規表現は、`　.+`です。

```
秋の田のかりほの盧のとまをあらみ そして輝く ウルトラソウル
春過て夏来にけらし白妙の そして輝く ウルトラソウル
……
百敷やふるき軒端の忍ふにも そして輝く ウルトラソウル
```

ﾊｲ

### 番外編 ウルトラソウル別解
最後に、必ずしも正規表現だけに頼らなくても良いよということについて。

```
天智天皇
001 秋の田のかりほの盧のとまをあらみ　我ころも手は露にぬれつゝ

持統天皇
002 春過て夏来にけらし白妙の　衣ほすてふあまの香来山

……(筆者による省略)

順徳院
100 百敷やふるき軒端の忍ふにも　なを餘りあるむかし成けり
```

半角スペースと全角スペースを`\t`(タブ)に変換し、Excelに貼り付けると……
![スクリーンショット 2021-02-24 18.18.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247157/d7ec71ed-d95a-c2d2-ea2e-7aaaff420b07.png)

綺麗に作者、上の句、下の句が分離できます。
あとは作者行、下の句行を削除し、ここまでの知識とExcelの標準機能を使って加工すれば、かなり簡単に目的のものが作れます。
いつも正規表現に頼る必要はないです。使えるときに使えるものを使っていきましょう。

# 終わりに
「こんなもん何に使うねん」と思われたかもしれませんが、結構使います。
筆者は最近のAWS障害で「再取り込み対象のデータをパラメータに変換する手段」として、ここで書いた内容を使うことになりました。

正規表現は丸暗記する必要はないです。でも、たまに正規表現チェッカーを使って作れるようになっておけば色々便利です。
たまに思い出してみてください。

[^3]: こちらの場合、最終行に改行があるなしに関わらず改行ができてしまうので、正確さを求めるのであれば結局はまずファイルを眺める必要があります。