プログラム言語 正規表現

概要

通常の文字列判定(Perl)
fnMatchCheck("I Love Perl");
→マッチ
fnMatchCheck("I love perl");
→マッチしない
sub fnMatchCheck
{
  my $target = shift;
  if ($target eq "I Love Perl")
  {
    print "マッチ!","\n";
  }
}

正規表現を用いた判定(Perl)
fnMatchCheck("I Love Perl");
→マッチ
fnMatchCheck("I love perl");
→マッチ
sub fnMatchCheck
{
  my $target = shift;
  if ($target =~ /I [lL]ove [pP]erl/)
  {
    print "マッチ!","\n";
  }
}

基本形

using System.Text.RegularExpressions;

string[] strCheck = {
  @"C#", ⇒マッチ!
  @"c#",
  @"C",
  @"c",
  @"I Love C#", ⇒マッチ!
  @"VB.NET",
  @"Perl",
  @"abcde",
  @"abcC#de", ⇒マッチ!
  };

Regex myReg = new Regex(pattern: @"C#");

foreach (string elm in strCheck)
{
  //elm は "C#"を含むか?
  if (myReg.IsMatch(input: elm))
  {
    Console.WriteLine("マッチ!");
  }
}

@」はエスケープ処理防止
(「プログラム言語 変数/リテラル」参照)

import re

正規表現パターンを定義
phone_num = re.compile(r'\d\d\d-\d\d\d\d-\d\d\d\d')

引数から正規表現パターンにマッチする値を検索
mo = phone_num.search('私の電話番号は050-3695-5892です')

マッチした値を取得
print('電話番号:{phone_num}'.format(phone_num=mo.group()))
→電話番号:050-3695-5892

ワイルドカード「.」探索に改行を含める
pattern = re.compile(r'文字列', re.DOTALL)

大文字小文字を区別せず探索する
pattern = re.compile(r'文字列', re.IGNORECASE)
pattern = re.compile(r'文字列', re.I)

正規表現について改行、コメント可能に
pattern = re.compile(r'文字列', re.VERBOSE)

オプションの組み合わせ(「|」で繋ぐ)
pattern = re.compile(r'文字列', re.DOTALL | re.IGNORECASE)

文字列 =~ /検索語/
文字列 は 検索語 を含むか?

fnMatchCheck("I Love Perl");
→マッチ!

sub fnMatchCheck
{
  my $target = shift;
  # $target は Perl を含むか?
  if ($target =~ /Perl/)
  {
    print "マッチ!","\n";
  }
}

否定形
文字列 !~ /検索語/
文字列 は 検索語 を含まないか?

fnMatchCheck("I Love Perl");
→アンマッチ!

sub fnMatchCheck
{
  my $target = shift;
  # $target は Ruby を含まないか?
  if ($target !~ /Ruby/)
  {
    print "アンマッチ!","\n";
  }
}

正規表現

一覧

a*a

a、aa、9a、a9

表現 機能 使用例 結果
. 任意の1文字 a.a a9a、aaa
* 直前の1文字の0回以上の繰り返し
.* 直前の1文字の1回以上の繰り返し a.*a a99a、a9a、aaa、aa
+ 直前の1文字の1回以上の繰り返し a+a a99a、a9a、aa
? 直前の文字の0または1文字 a?a aaa、aa、9aa
^ 行の先頭 ^a aaa、aa、a9
$ 行の末尾 a$ aaa、aa、9a
[] カッコ内の任意の文字 [123]
[1-3]も可
a1、2a、a123b
[^] カッコ内の任意の文字以外 [^1-3] aa、9a
{n} n回繰り返し a{2} aa、aaa、9aa、aa9
{n,} n回以上繰り返し a{2,} aa、aaa、9aa、aa9
{n,m} n~m回繰り返し a{2,4} aa、aaa、aaaa、9aaa
~1|~2 ~1 または ~2 aa|99 aaa、a99、aab99
\ 直後の一文字を非正規表現として扱う \[、\?、\. [aa、a?、a.

メタキャラクタ

表現 機能
\w 英字 a~z、A~Z、_、1~9
\W 英字以外
\s 空白文字 半角スペース、タブ、改行、キャリッジリターン
\S 空白文字以外
\d 半角数字 0~9
\D 半角数字以外
\b 単語の境界

任意の一文字

[検索語]
検索語の中の一文字 を含むか?

string[] strCheck = {
  @"C#", ⇒マッチ!
  @"c#", ⇒マッチ!
  @"C", ⇒マッチ!
  @"c", ⇒マッチ!
  @"I Love C#", ⇒マッチ!
  @"VB.NET",
  @"Perl",
  @"abcde", ⇒マッチ!
  @"i love c#", ⇒マッチ!
  };

// elm は「c」か「C」を含むか?
Regex myReg = new Regex(pattern: @"[cC]");

foreach (string elm in strCheck)
{
  if (myReg.IsMatch(elm))
  {
    Console.WriteLine("マッチ!");
  }
}

import re

pattern = re.compile(r'[pP]')
mo = pattern.findall('phpPHPpythonPYTHONjavaJAVA')
mo # ['p', 'p', 'P', 'P', 'p', 'P']
mo[0] # p(小文字)
mo[1] # p(小文字)
mo[2] # P(大文字)
mo[3] # P(大文字)

連続を定義する場合
[a-zA-Z0-9]

記号を定義する場合
[.]
↓の様にエスケープ不要
[\.]

補集合
定義した文字列でない文字列を検索
pattern = re.compile(r'[^pP]')
mo = pattern.findall('phpPHPpythonPYTHONjavaJAVA')
mo # ['h', 'H', 'y', 't', 'h', 'o', 略]
mo[0] # h
mo[1] # H

文字列 =~ /[検索語]/
文字列 は 検索語の中の一文字 を含むか?

fnMatchCheck("I Love Perl");
→マッチ!
fnMatchCheck("I love perl");
→マッチ!

sub fnMatchCheck
{
  my $target = shift;
  # $target は p or P を含むか?
  if ($target =~ /[pP]/)
  {
    print "マッチ!","\n";
  }
}

任意の一文字(連続)
[ag]
⇒[abcdefg]

fnMatchCheck("c;);
→マッチ!

sub fnMatchCheck
{
  my $target = shift;
  # $target は abcdefg・・・vwxyz の中の一文字を含むか?
  if ($target =~ /[a-z]/)
  {
    print "マッチ!","\n";
  }
}

任意の一文字の否定
文字列 =~ /[^検索語]/
文字列 は 検索語の中の一文字 を含まないか?

fnMatchCheck("hijklmn");
→マッチ!

sub fnMatchCheck
{
  my $target = shift;

  # $target は abcdefg の中の一文字を含まないか?
  if ($target =~ /[^a-g]/)
  {
    print "マッチ!","\n";
  }
}

ワイルドカード(一文字)


何か一文字 を含むか?

string[] strCheck = {
  @"get", ⇒マッチ!
  @"gt",
  @"g",
  @"t",
  @"got", ⇒マッチ!
  @"ghost",
  @"I get pass" ⇒マッチ!
  };

// elm は 先頭「g」、間に何か一文字、末尾「t」の文字を含むか?
Regex myReg = new Regex(pattern: @"g.t");

foreach (string elm in strCheck)
{
  if (myReg.IsMatch(elm))
  {
    Console.WriteLine("マッチ!");
  }
}

import re

pattern = re.compile(r'.at')
mo = pattern.findall('The cat in the hat sat on the flat mat.')
mo # ['cat', 'hat', 'sat', 'lat', 'mat']
mo[0] # cat

pattern = re.compile(r'Language: (.*) Frame Work: (.*)')
mo = pattern.search('Language: php Frame Work: CakePHP3, Laravel')
mo.group() # Language: php Frame Work: CakePHP3, Laravel
mo.group(1) # php
mo.group(2) # CakePHP3, Laravel

最短探索
pattern = re.compile(r'<.*?>')
mo = pattern.search('Language: <php> Frame Work: <CakePHP3, Laravel>')
mo.group() # <php>

最長探索
pattern = re.compile(r'<.*>')
mo = pattern.search('Language: <php> Frame Work: <CakePHP3, Laravel>')
mo.group() # <php> Frame Work: <CakePHP3, Laravel>

ワイルドカード「.」探索に改行を含める
pattern = re.compile(r'文字列', re.DOTALL)

文字列 =~ / ~~ /
文字列 は ~何か一文字~ を含むか?

fnMatchCheck("get");
→マッチ!
fnMatchCheck("ghost");
→マッチしない
fnMatchCheck("I’ve got a pass");
→マッチ!

sub fnMatchCheck
{
  my $target = shift;
  # $target は g(何か一文字)t を含むか?
  if ($target =~ /g.t/)
  {
    print "マッチ!","\n";
  }
}

量指定子

「?」(0個or1個)

string[] strCheck = {
  @"get", ⇒マッチ!
  @"gt", ⇒マッチ!
  @"g",
  @"t",
  @"got", ⇒マッチ!
  @"ghost",
  @"I get pass" ⇒マッチ!
  @"gto = great teacher onizuka"; ⇒マッチ!
  };

// elm は 先頭「g」、間に何か0文字or一文字、末尾「t」の文字を含むか?
Regex myReg = new Regex(pattern: @"g.?t");

foreach (string elm in strCheck)
{
  if (myReg.IsMatch(elm))
  {
    Console.WriteLine("マッチ!");
  }
}

import re

pattern = re.compile(r'Bat(wo)?man')
mo = pattern.search('The Adventures of Batman')
print(mo.group()) # Batman

mo = pattern.search('The Adventures of Batwoman')
print(mo.group()) # Batwoman

pattern = re.compile(r'(\d{3}-)?\d{4}-\d{4}')
mo = pattern.search('電話番号は050-3695-589244です。')
mo.group() # 050-3695-5892

mo = pattern.search('電話番号は3695-589244です。')
mo.group() # 3695-5892

pattern = re.compile(r'aa\d?aa')
mo = pattern.search('__aa555aa__')
mo # None

pattern = re.compile(r'aa\d?aa')
mo = pattern.search('__aa5aa__')
mo.group() # aa5aa

pattern = re.compile(r'aa\d?aa')
mo = pattern.search('__aaaa__')
mo.group() # aaaa

pattern = re.compile(r'aa\d?aa')
mo = pattern.search('__aaa__')
mo # None

文字列 =~ / ~? /
文字列 は ~を0文字か1文字 を含むか?

例:ab?
⇒「a」 または 「ab」にマッチ
例:a.?
⇒「a」 または 「ad」「ab」…「az」や、「a0」…「a9」にマッチ

fnMatchCheck("gt");
→マッチ!
fnMatchCheck("get");
→マッチ!
fnMatchCheck("ghost");
→マッチしない

sub fnMatchCheck
{
  my $target = shift;

  if ($target =~ /g.?t/)
  {
   # $target は g(何かの文字0文字か1文字)t を含むか?
    print "マッチ!","\n";
  }
}

「+」(1個以上)

string[] strCheck = {
  @"get", ⇒マッチ!
  @"gt",
  @"g",
  @"t",
  @"got", ⇒マッチ!
  @"ghost", ⇒マッチ!
  @"I get pass" ⇒マッチ!
  @"gto = great teacher onizuka";
  };

// elm は 先頭「g」、間に何か一文字以上、末尾「t」の文字を含むか?
Regex myReg = new Regex(pattern: @"g.+t");

foreach (string elm in strCheck)
{
  if (myReg.IsMatch(elm))
  {
    Console.WriteLine("マッチ!");
  }
}

import re

pattern = re.compile(r'Bat(wo)+man')

mo = pattern.search('The Adventures of Batman')
mo # None

mo = pattern.search('The Adventures of Batwoman')
mo.group() # Batwoman

mo = pattern.search('The Adventures of Batwowowoman')
mo.group() # Batwowowoman

文字列 =~ / ~+ /
文字列 は ~を1個以上 を含むか?

例:ab+
⇒「ab」「abb」「ab0」…にマッチ
例:a.+
⇒「aa」「ab」「abc」…にマッチ

fnMatchCheck("gt");
→マッチしない
fnMatchCheck("get");
→マッチ!
fnMatchCheck("ghost");
→マッチ!

sub fnMatchCheck
{
  my $target = shift;

  if ($target =~ /g.+t/)
  {
   # $target は g(何かの文字1個以上)t を含むか?
    print "マッチ!","\n";
  }
}

「*」(0個以上)

string[] strCheck = {
  @"get", ⇒マッチ!
  @"gt", ⇒マッチ!
  @"g",
  @"t",
  @"got", ⇒マッチ!
  @"ghost", ⇒マッチ!
  @"I get pass" ⇒マッチ!
  @"gto = great teacher onizuka"; ⇒マッチ!
  };

// elm は 先頭「g」、間に何か0文字以上、末尾「t」の文字を含むか?
Regex myReg = new Regex(pattern: @"g.*t");

foreach (string elm in strCheck)
{
  if (myReg.IsMatch(elm))
  {
    Console.WriteLine("マッチ!");
  }
}

import re

pattern = re.compile(r'Bat(wo)*man')

mo = pattern.search('The Adventures of Batman')
mo.group() # Batman

mo = pattern.search('The Adventures of Batwoman')
mo.group() # Batwoman

mo = pattern.search('The Adventures of Batwowowoman')
mo.group() # Batwowowoman

文字列 =~ / ~* /
文字列 は ~を0文字以上 を含むか?

例:ab*
⇒「a」「ab」「abb」「ab0」…にマッチ
例:a.*
⇒「a」「aa」「ab」「abc」…にマッチ

fnMatchCheck("gt");
→マッチ!
fnMatchCheck("get");
→マッチ!
fnMatchCheck("ghost");
→マッチ!

sub fnMatchCheck
{
  my $target = shift;

  if ($target =~ /g.*t/)
  {
   # $target は g(何かの文字0個以上)t を含むか?
    print "マッチ!","\n";
  }
}

「{n}」(n個連続)
「{n,}」(n個以上連続)
「{n,m}」(n個以上m個以下連続)

string[] strCheck1 = {
  @"gt",
  @"get",
  @"geet",
  @"geeet" ⇒マッチ!,
  @"geeeet",
  @"g",
  @"t",
  @"ghost" ⇒マッチ!,
  @"I see ghost." ⇒マッチ!;
  };

// elm は 先頭「g」、間に何か三文字、末尾「t」の文字を含むか?
Regex myReg1 = new Regex(pattern: @"g.{3}t");

foreach (string elm in strCheck1)
{
  if (myReg1.IsMatch(elm))
  {
    Console.WriteLine("マッチ!");
  }
}

string[] strCheck2 = {
  @"gt",
  @"get", ⇒マッチ!
  @"geet", ⇒マッチ!
  @"geeet", ⇒マッチ!
  @"geeeet",
  @"g",
  @"t",
  @"ghost" ⇒マッチ!,
  @"I see ghost." ⇒マッチ!
  };

// elm は 先頭「g」、間に何か1~3文字、末尾「t」の文字を含むか?
Regex myReg2 = new Regex(pattern: @"g.{1,3}t");

foreach (string elm in strCheck2)
{
  if (myReg2.IsMatch(elm))
  {
    Console.WriteLine("マッチ!");
  }
}

string[] strCheck3 = {
  @"gt",
  @"get",
  @"geet",
  @"geeet", ⇒マッチ!
  @"geeeet", ⇒マッチ!
  @"g",
  @"t",
  @"ghost" ⇒マッチ!,
  @"I see ghost." ⇒マッチ!;
  };

// elm は 先頭「g」、間に何か三文字以上、末尾「t」の文字を含むか?
Regex myReg3 = new Regex(pattern: @"g.{3,}t");

foreach (string elm in strCheck3)
{
  if (myReg3.IsMatch(elm))
  {
    Console.WriteLine("マッチ!");
  }
}

import re

phone_num_pattern = re.compile(r'\d\d\d-\d\d\d\d-\d\d\d\d')
↑と同じ
phone_num_pattern = re.compile(r'\d{3}-\d{4}-\d{4}')
mo = phone_num_pattern.search('aaaaaaa050-3695-589244444ddddddddd')
mo.group() 050-3695-5892

文字列 =~ / ~{n} /
文字列 は ~をn個連続 を含むか?

例:ge{2}t
⇒「geet」にマッチ。get:×、gt:×

fnMatchCheck("get");
→マッチしない
fnMatchCheck("geet");
→マッチ!
fnMatchCheck("geeet");
→マッチしない

sub fnMatchCheck
{
  my $target = shift;

  if ($target =~ /ge{2}t/)
  {
    print "マッチ!","\n";
  }
}

最長/最短一致「正規表現」?

import re

最長マッチ/貪欲マッチ
pattern = re.compile(r'(php){3,5}')
mo = pattern.search('phpphpphpphp')
mo.group() # phpphpphpphp
最も長い文字列を検索

最短マッチ/非貪欲マッチ
pattern = re.compile(r'(php){3,5}?')
mo = pattern.search('phpphpphpphp')
mo.group() # phpphpphp
最も短い文字列を検索

位置指定子

「^」 先頭

例: "^\d"
"555" ○
"5aa" ○
"a55" ×
import re

phone_num_pattern = re.compile(r'^\d{3}-\d{4}-\d{4}')
mo = phone_num_pattern.search('aaaaaaa050-3695-589244444ddddddddd')
mo None

phone_num_pattern = re.compile(r'^\d{3}-\d{4}-\d{4}')
mo = phone_num_pattern.search('050-3695-589244444ddddddddd')
mo.group() 050-3695-5892

phone_num_pattern = re.compile(r'^\d{3}-\d{4}-\d{4}$')
mo = phone_num_pattern.search('050-3695-5892')
mo.group() #050-3695-5892

「$」 末尾

ただし、文字列の末尾が \n の時は、その前と一致。
(末尾が \n でも末尾で一致させるには、\z を使う。)

例: "\d$"
"555" ○
"aa5" ○
"55a" ×
import re

phone_num_pattern = re.compile(r'\d{3}-\d{4}-\d{4}$')
mo = phone_num_pattern.search('aaaaaaa050-3695-589244444ddddddddd')
mo None

phone_num_pattern = re.compile(r'\d{3}-\d{4}-\d{4}$')
mo = phone_num_pattern.search('aaaaaaa050-3695-5892')
mo.group() 050-3695-5892

phone_num_pattern = re.compile(r'^\d{3}-\d{4}-\d{4}$')
mo = phone_num_pattern.search('050-3695-5892')
mo.group() #050-3695-5892

代替構成体「|」

import re

pattern = re.compile(r'php|python')
mo = pattern.search('私はpythonとphpが得意です')
mo.group() # python

mo = pattern.search('私はphpとpythonが得意です')
mo.group() # php

mo = pattern.findall('私はpythonとphpが得意です')
mo # ['python', 'php']
mo[0] # python
mo[1] # python

グループ化構成体「()」

import re

pattern = re.compile(r'(\d{3})-(\d{4})-(\d{4})')
mo = pattern.search('私の電話番号は050-3695-5892です')
mo.group() # 050-3695-5892
mo.group(0) # 050-3695-5892
mo.group(1) # 050
mo.group(2) # 3695
mo.group(3) # 5892

mo.groups() # ('050', '3695', '5892')

置換

import re

pattern = re.compile(r'Language: \w+')
mo = pattern.sub(置換する文字, 置換する前の文字列)
mo = pattern.sub('php', 'Language: XXX / Frame Work: CakePHP3')
mo
php / Frame Work: CakePHP3

pattern = re.compile(r'Agent \w+')
mo = pattern.sub('Agent *****', 'Agent Alice told Agent Carol that Agent Eve knew Agent Bob.')
mo
Agent ***** told Agent ***** that Agent ***** knew Agent *****.

pattern = re.compile(r'Agent (\w)\w*')
グループ1にマッチした文字列に対して、\1を置換する
この場合は(\w) =Agent の後の最初の1文字で置換
mo = pattern.sub(r'\1****', 'Agent Alice told Agent Carol that Agent Eve knew Agent Bob.')
mo
A**** told C**** that E**** knew B****.

pattern = re.compile(r'Agent (\w)\w*')
mo = pattern.sub('*****', 'Agent Alice told Agent Carol that Agent Eve knew Agent Bob.')
mo
***** told ***** that ***** knew *****.

変数 =~ s/置換対象/置換後/;

my $s = "i love perl";
$s =~ s/i/I/;
⇒$s : I love perl

my $s = "I love perl";
$s =~ s/love/LOVE/;
$s =~ s/perl/PERL/;
⇒$s : I LOVE PERL

マッチした値の取得

if (文字列 =~ /(検索語)/)
{
  print "$1","\n";
  ⇒ 検索語
  # マッチした場合、検索語が$1に入る。
}

my $words_ref = [
  'papix loves meat!',
  'boolfool loves sushi!',
];

check($words_ref);

sub check
{
 my $str = shift;

 for my $elm (@$str)
 {
  if ($elm =~ /(.+) loves (.+)!/)
  {
   print "$1 => $2","\n";
   ⇒ papix => meat
   ⇒ boolfool => sushi
  }
 }
}

SQLでの利用

SQL DML:データ型/WHERE句における文字指定」参照

1週間でできる会員サイト「Limited」

1週間でできる会員サイト「Limited」
必要最小限。だから分かりやすい。始めやすい。続けやすい。
限定① 安⼼・安全の会員制
限定② 必要最⼩限の機能
限定③ 独⾃機能を追加可能