文字集合(いずれか1文字にマッチする正規表現)

文字集合(いずれか1文字にマッチする正規表現)

文字集合(文字セット)

 [ ] で囲まれた文字列は、その中のいずれか1文字にマッチする正規表現 (文字集合:set of characters) です。たとえば、[abc] は a, b, c のいずれかにマッチします。

# PYTHON_REGEX_CHARACTERS

# In[1]

import re

# a, b, c のいずれかに適合する正規表現
regex = re.compile(r'[abc]')

# 検索対象文字列
line = 'apple berry pie'

# lineを検索して適合する文字をすべて取得
f = regex.findall(line)

print(f)
# ['a', 'b']

 [ ] で囲んんだ文字列の先頭に ^ をつけると否定の意味になります。たとえば、[^abc] は a, b, c のいずれでもない文字すべてにマッチします(スペースなども含まれます)。すなわち、[^abc][abc] の補集合です。

# In[2]

# a, b, c のいずれでもない文字に適合する正規表現
regex = re.compile(r'[^abc]')

# 検索対象文字列
line = 'apple berry pie'

# lineを検索して適合する文字をすべて取得
f = regex.findall(line)

print(f)
# ['p', 'p', 'l', 'e', ' ', 'e', 'r', 'r', 'y', ' ', 'p', 'i', 'e']

連続する文字の集合

 アスキーコードや JISコードにおいて連続する数字や文字は、ハイフン(-)を使って間の文字を省くことができます。たとえば、[a-e][abcde] と同じ意味をもちます。

# PYTHON_REGEX_CONTINUOUS_CHARACTER_SET

# In[1]

import re

# a, b, c, d, e のいずれかに適合する正規表現
regex = re.compile(r'[a-e]')

# 検索対象文字列
line = 'abcdefg'

# lineを検索して適合する文字をすべて取得
f = regex.findall(line)

print(f)
# ['a', 'b', 'c', 'd', 'e']

 ハイフンを使って複数パターンをまとめることもできます。
 たとえば、[a-c1-3][abc123] と同じ表現です。

# In[2]

# a, b, c, 1, 2, 3 のいずれかに適合する正規表現
regex = re.compile(r'[a-c123]')

# 検索対象文字列
line = 'abcde12345'

# lineを検索して適合する文字をすべて取得
f = regex.findall(line)

print(f)
# ['a', 'b', 'c', '1', '2', '3']

 [ ] の中ではメタ文字が認識されないという特徴があります。たとえば、[abc?] の中にある ? はメタ文字ではなく、単に検索対象から ? という文字を探すという意味です。

# In[3]

# a, b, c, ? のいずれかに適合する正規表現
regex = re.compile(r'[abc?]')

# 検索対象文字列
line = 'Do you have a dog?'

# lineを検索して適合する文字をすべて取得
f = regex.findall(line)

print(f)
# ['a', 'a', '?']

特殊シーケンス

 Python の正規表現には \ で始まる 特殊シーケンスとよばれる文字集合が用意されています。たとえば、\d は 1 桁の数字を表します。ただし、これは [0-9] と同じ意味をもつわけではありません。\d は全角数字なども含むからです。

# PYTHON_REGEX_ESCAPE_SEQENCE

# In[1]

import re

# 正規表現オブジェクトを作成
regex = re.compile('\d\d')

# 検索対象文字列
line_1 = '平成30年12月21日'
line_2 = '2018年2月5日'

# lineを検索して適合する文字をすべて取得
f1 = regex.findall(line_1)
f2 = regex.findall(line_2)

print(f1)
print(f2)

# ['30', '12', '21']
# ['20', '18']

 このように、\d は誤解を招きやすい表現でああることから、数字の集合は [0-9][0-9] のように書くべきだと主張する人もいます。
 
 \w は任意の文字を表す特殊シーケンスです。
 英単語を構成する文字だと解説している本やサイトが多いのですが、これは誤解であり、実際には あいうえお のような平仮名や、αβγδε のようなギリシア文字など、ほとんどあらゆる文字にマッチします。

# In[2]

# 正規表現オブジェクトを作成
regex = re.compile('\w')

# 検索対象文字列
line_1 = 'cat'
line_2 = 'ねこ'
line_3 = '猫'

# lineを検索して適合する文字をすべて取得
f1 = regex.findall(line_1)
f2 = regex.findall(line_2)
f3 = regex.findall(line_3)

print(f1)
print(f2)
print(f3)

# ['c', 'a', 't']
# ['ね', 'こ']
# ['猫']

 \s はスペースを意味する特殊シーケンスです。

# In[3]

# 正規表現オブジェクトを作成
regex = re.compile('\s')

# 検索対象文字列
line = 'I have a cat.'

# lineを検索して適合する文字をすべて取得
f = regex.findall(line)

print(f)
# [' ', ' ', ' ']

 この他にも、\D, \W, \S のような特殊シーケンスがあります。それぞれ、\d, \w, \s の補集合であり、「数字ではない」、「文字ではない」、「スペースではない」要素の集合を意味しています。
 

文章中から英単語を抜き出す

 文字集合と 1 回以上の繰返しを表す + を組合わせて、[a-zA-z]+ という正規表現を使うと、文章中から英字で構成された単語を取り出すことができます。

# In[4]

import re

# 検索対象文字列
my_str = '好きなフルーツはappleとorangeです'

# 英字単語にマッチする正規表現オブジェクトを作成
regex = re.compile(r'[a-zA-z]+')

# 単語を抽出
f = regex.findall(my_str)

print(f)
# ['apple', 'orange']

 英文に適用すると文章を単語に分割します。

# In[5]

# reモジュールをインポート
import re

# 検索対象文字列
my_str = 'I love strawberry.'

# 英字単語にマッチする正規表現オブジェクトを作成
regex = re.compile(r'[a-zA-z]+')

# 単語を抽出
f = regex.findall(my_str)

print(f)
# ['I', 'love', 'strawberry']