split x but not xx ~正規表現を用いて実現~


問題

文字列を特定の区切り文字(例えばx)で分割したいが、その特定の文字列が二つ続いていた場合(例えばxx)は分割したくない、という時、どのような正規表現を用いれば実現できるか。

つまり、split x but not xx はどのように実現できるか。



どのような場面で必要だったか

蛇足にはなりますが、これがどのような場面で必要だったのか、という事を共有させていただきます。

URLを分割きれいに分割したかった

やりたかったことは、例えばhttps://hoge.com/dir1/dir2/dir3というURLがあった時に、『https://hoge.com』『dir1』『dir2』『dir3』に分割することでした。

普通に分割すると…

しかし、普通に / (スラッシュ)で分割しようとすると、下記のようになってしまします。
※下記はPythonを使用した例です。

そこで split x but not xx を実現する正規表現を模索しました。

url = "https://hoge.com/dir1/dir2/dir3"
dirs = url.split('/')
print(dirs)

#出力  :['https:', '', 'hoge.com', 'path1', 'path2', 'path3']
#望む出力:['https://hoge.com', 'path1', 'path2', 'path3']





正規表現の先読み・後読み

正規表現には先読み・後読みなるものがあるらしく、これを用いることにします。

※先読み・後読みの理解にはこちらの記事に大変助けられました。
https://www.tohoho-web.com/ex/regexp.html#lookaround_assertion


先読み・後読みには否定形を合わせて種類が4つあるらしく、下記に簡単に記します。

先読み  :特定の文字が後ろに続く場合のみマッチ
否定先読み:特定の文字が後ろに続かない場合のみマッチ
後読み  :特定の文字が前に存在する場合のみマッチ
否定後読み:特定の文字が前に存在しない場合のみマッチ

文字だけ見てもなんのこっちゃという感じかもしれないので、プログラムを用いて、確認していきましょう。
ちなみに今回は否定先読み否定後読みの二つを使用します。




Pythonで 否定先読み・否定後読みを学ぶ

まずはPythonで否定先読みを使用して、分割してみます。
Pythonで正規表現を用いた分割にはreモジュールが必要なようです。

否定先読み

下記は否定先読みを使用して、/ (スラッシュ) が後ろに続かない / (スラッシュ) のみ分割するという事を行っています。
https: の後の / (スラッシュ) は後ろに / (スラッシュ) が続いていたため、分割対象にならず残っています。

import re

url = "https://hoge.com/dir1/dir2/dir3"
dirs = re.split('/(?!/)', url)
print(dirs)

#出力:['https:/', 'hoge.com', 'dir1', 'dir2', 'dir3']

否定後読み

次は否定後読みを見てみましょう。
下記は否定後読みを使用して、/ (スラッシュ) が前に存在しない / (スラッシュ) のみ分割するという事を行っています。
hoge.com の前の / (スラッシュ) は前に / (スラッシュ) が存在していたため、分割対象にならず残っています。

import re

url = "https://hoge.com/dir1/dir2/dir3"
dirs = re.split('(?<!/)/', url)
print(dirs)

#出力: ['https:', '/hoge.com', 'dir1', 'dir2', 'dir3'] 




Pythonで split x but not xx

では上記で学んだ 否定先読み・否定後読みを組み合わせて split x but not xx を実現してみます。
実現できました!

/ (スラッシュ)が前にも後にもない / (スラッシュ) のみ 分割するためhttps: のあとの // は分割対象にならずに残っています。

import re

url = "https://hoge.com/dir1/dir2/dir3"
dirs = re.split('(?<!/)/(?!/)', url)
print(dirs)

#出力: ['https://hoge.com', 'dir1', 'dir2', 'dir3']



正規表現は使用している言語によって書き方が違ったりすると思うので、他の言語で行う時はその言語に合わせた書き方が必要になります。
下記にPHPとJavascriptで行う場合のサンプルを載せておきます。


PHPで split x but not xx

PHPで正規表現を用いて分割を行う場合は preg_split を使用するようです。
スラッシュはバックスラッシュでエスケープする必要があります。

$url = "https://hoge.com/dir1/dir2/dir3";
$dirs = preg_split("/(?<!\/)\/(?!\/)/", $url);
var_dump($dirs);

//出力:array(4) { [0]=> string(16) "https://hoge.com" [1]=> string(4) "dir1" [2]=> string(4) "dir2" [3]=> string(4) "dir3" }




Javascriptで split x but not xx

Javascriptで正規表現を用いて分割を行う場合は通常の分割と同じsplitで出来るようです。

let url = "https://hoge.com/dir1/dir2/dir3"
let dirs = url.split(/(?<!\/)\/(?!\/)/)
console.log(dirs)

//出力:(4) ['https://hoge.com', 'dir1', 'dir2', 'dir3']





以上、正規表現を用いて split x but not xx を実現する方法でした。

正規表現はちょっと気分が重く避けてきてしまってたのですが、理解できると嬉しいものですね。

参考になれば幸いです!

コメント

タイトルとURLをコピーしました