プログラム言語 正規表現
目次
概要
通常の文字列判定(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";
}
}
基本形
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("マッチ!");
}
}
「@」はエスケープ処理防止
(「プログラム言語 変数/リテラル」参照)
正規表現パターンを定義
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";
}
}
正規表現
一覧
表現 | 機能 | 使用例 | 結果 |
---|---|---|---|
. | 任意の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 | 単語の境界 |
任意の一文字
[検索語]
検索語の中の一文字 を含むか?
@"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("マッチ!");
}
}
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";
}
}
任意の一文字(連続)
[a–g]
⇒[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";
}
}
ワイルドカード(一文字)
.
何か一文字 を含むか?
@"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("マッチ!");
}
}
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個)
@"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("マッチ!");
}
}
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個以上)
@"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("マッチ!");
}
}
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個以上)
@"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("マッチ!");
}
}
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個以下連続)
@"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("マッチ!");
}
}
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個連続 を含むか?
例:ge{2}t
⇒「geet」にマッチ。get:×、gt:×
fnMatchCheck("get");
→マッチしない
fnMatchCheck("geet");
→マッチ!
fnMatchCheck("geeet");
→マッチしない
sub fnMatchCheck
{
my $target = shift;
if ($target =~ /ge{2}t/)
{
print "マッチ!","\n";
}
}
最長/最短一致「正規表現」?
最長マッチ/貪欲マッチ
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
最も短い文字列を検索
位置指定子
「^」 先頭
"555" ○
"5aa" ○
"a55" ×
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 を使う。)
"555" ○
"aa5" ○
"55a" ×
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
代替構成体「|」
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
グループ化構成体「()」
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')
置換
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 *****.
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
マッチした値の取得
{
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
}
}
}