Gaiax TechEgg's Blog

非エンジニアがエンジニアを目指すブログ

基礎① 8.正規表現をやってみた

みなさんにお知らせがあります!
このブログの元になっている資料が公開されました!

github.com


私はこれを元に勉強してきたので、皆さんも参考にしてみてください。
さて今回はもっともperlらしいといわれる「正規表現」には入ります!

エンジニア基礎①
1. Perl環境基礎
2. Hello,world!
3. Perl基礎
4. 配列・for文
5. ハッシュ
6. リファレンス
7. サブルーチン
8. ⭐️ 正規表現 ⭐️
9. Amon2 入門 第一部
10. Amon2 入門 第二部

ゴール?(めやす:30分)


おさえておきたいこと


正規表現

正規表現とは、幾つかの文字列を一つの形式で表すための表現方法です。正規表現によって、必要としているものを、膨大な文字列の中から自由自在に検出したり、置き換えたりすることができます。例えば、「検索機能」を実装する!ってなったときは、この正規表現を用いれば、「○○を含む検索」などのキーワードの設定ができるわけです!
でも、この正規表現はとても複雑なので、よく使うもの、基本的なものだけを紹介します!

メタ文字

正規表現で、幾つかの文字に対して特別な意味を与えています。これらを「メタ文字」といいます。

. ^ $ [ ] * + ? | ( )

これらのメタ文字を使って、条件にあったものがあるかどうか判定します!

いざスタート!


1. パターンマッチ

◼︎完全一致 eq

my $str = "pattern match!";
if  ( $str eq 'match') { 
      print "'$str'できました!\n";
}else{
      print "完全一致しませんでした。\n";
}

完全一致しませんでした。

eqは完全一致か否かをみます。
この場合$strmatchが完全一致しているのかをみているので、表示結果は「完全一致しませんでした。」になります。

◼︎含む =~ /文字/ /含まない !~ /文字/

my $str = "pattern match!";

if ( $str =~ /match/) {
  print "'$str'は'match'を含みます!\n";
}
if ( $str !~ /match/) {
  print "'$str'は'perl'を含みません。\n";
}

'pattern match!'は'match'を含みます!

=~ /match/=/ここに入った文字/が含まれると一致
!~ /match/=/ここに入った文字/が含まれないと一致

含む、含まないは以上のように表記することでパターンマッチすることができます。

2.文字列のマッチ

メタ文字を駆使して文字列を呼び出すことができます。

◼︎文字列の呼び出し

my $word = "五反田にはガイアックスがあるらしい";
if ( $word =~ /五反田(.+)ある/) {
  print "渋谷$1ない\n";
}

渋谷にはガイアックスがない

(.+)は任意の文字に一回以上マッチしたものを取得するので、(.+)には「五反田」と「ある」の間の「にはガイアックスが」が入ります。それを$1の変数として取得しています。これは複数個連ねることもできます。

◼︎複数個の文字列の呼び出し

my $word = "五反田にはガイアックスというIT系企業が多い";
if ( $word =~ /五反田には(.+)という(.+)/) {
  print "渋谷には$1はないが、$2\n";
}

渋谷にはガイアックスがないが、IT系企業が多い

前者の(.+)は$1、後者の(.+)は$2と、(.+)が複数ある場合は先頭から順に取得しています。

3.メタ文字

先ほど紹介した以外のよく使うメタ文字一覧

メタ文字 役割
. ピリオド。ワイルドカード:任意の一文字にマッチ!
* 直前におかれているものに0回以上マッチ!
.* 任意の文字に任意の回数マッチ!
+ 直前に置かれているものに1回以上マッチ!
.+ 任意の文字に一回以上マッチ!
? 直前のものが、1回現れるか、現れない、の2択!
( ) パターンをグループ化にしてマッチ!($1などで後方参照できます)
(?:) 後方参照しないグループ化!
\w アルファベット, 数字, アンダーバーの1文字
\W アルファベット, 数字, アンダーバー以外の1文字
\d 数字の1文字
\D 数字以外の1文字
\s 空白文字にマッチ
\S 空白文字以外にマッチ
\b 単語の境界(置いた前後)とマッチ
\B 単語の境界以外とマッチ
^ 行頭の文字列とマッチ
$ 行末の文字列とマッチ


これらの知識を使って、文字列のパターンマッチをしましょう!

【例1】
複数あるものの中から、必要な情報があるか確認できます。
「y」を含む言葉があるかどうか判定したい時、以下のようにします。

my $color = "red blue orange green yellow black white";
if ( $color =~ /y(.+)/) {
  print "あてはまるものはあったよ!\n";
}else{
  print "あてはまるものはなかったよ!\n";
}

あてはまるものはあったよ!


y(.+)は「y」と「なんらかの文字を含む」のを条件にしています。
今回は「yellow」があるので、「あてはまるものがあったよ!」に判定されました。
もし「skyblue」があった場合もマッチします!

「y」からはじまる言葉があるかどうかを判定したい時、以下のようにします。

my $color = "red blue orange green yellow black white";
if ( $color =~ /\b(y\S+)/) {
  print "y からはじまる単語 $1 がありました。\n";
}else{
  print "yからはじまる単語は見つかりませんでした。\n";
}

y からはじまる単語 yellow がありました。

これは2行目の(y\S+)で「yに続く文字が空白文字以外である」ことを判定し、\b(y\S+)\bを付け加えることで、「yの直前になにもなく(=yではじまる)、直後に空白文字以外が続く」ことを判定します。
よって、「yellow」がマッチするのです!

【例2】
もしなにかのサービスで新規ユーザの登録をするとき、よくみかける「アルファベット、数字、アンダーバーのみ使用可」というのもこの正規表現で判定することができます。

my $username = "marimo";
if ( $username =~ /\W/ ){
  print "アルファベット、数字、アンダーバーを使用してください。";
}else{
  print "登録可能です。";
}

登録可能です。

もし「marimo」ではなく「marimo*」をusernameで使用すると、「アルファベット、数字、アンダーバーを使用してください。」と表示されます!
1行目のmarimomy $input = <STDIN>;にして試してみてください!

【例3】変数として扱うこともできます。
もしなにかのサービスで子供が安全に使えるように検索機能で「凶暴」という言葉を制限するとします。

my $input = <STDIN>;
if ( $input =~ /凶暴/) {
  print "この言葉は検索できません。\n";
}else{
  print "検索結果を表示します。\n";
} 

↓凶暴と打った場合

この言葉は検索できません。

↓安全と打った場合

検索結果を表示します。

以上、正規表現を用いた例でした!

4.置換

s/置換したい文字/置換した後の文字/というふうにおくと置換できます。

my $word = "red blue yellow";
print "$word\n";
$word =~ s/red/orange/;
print "$word\n";

red blue yellow
orange blue yellow

1行目が置換前、2行目が置換後の文字列が表示されました!
例えば、今日の会議だけ、開始時間が一時的に変更になったとき、2行目を足せば大丈夫!

my $action = "今日の会議は10:00開始です。";
$action =~ s/10:00/12:00/;
print "$action\n";

今日の会議は12:00開始です。

--

以上が正規表現になります。
perlでの正規表現は分厚い本が一冊あるほど、奥が深いと言われています。。。
簡単な例を出して考えてみましたが、どんな風に使うか実感わいたでしょうか!?
メタ文字はこのほかにもいっぱいありますので、場合にあったメタ文字を探してくださいね!