LoginSignup
4
7

More than 5 years have passed since last update.

正規表現のまとめ

Last updated at Posted at 2018-06-16

正規表現(Regular expression, RE)

Web Scrapingを行っていると正規表現の知識が必要となりました。そこでlinuxとpythonによる正規表現をまとめました。ここでは、標準ライブラリreを使用します。

特殊文字 意味
. 任意の文字にマッチ。
^ (キャレット)文字列の先頭にマッチ csvTest.csvのとき^csvで先頭のcsvのみにマッチ
$ 文字列の末尾にマッチ csvTest.csvのときcsv$で末尾のcsvのみにマッチ
* 直前にあるREに作用してREを0回以上繰り返したものにマッチ
+ 直前にあるREに作用してREを1回以上繰り返したものにマッチ
? 直前にあるREに作用してREを0 or 1回繰り返したものにマッチ。 ab?cならac, abcとマッチ
{m} m回の正確なコピーとマッチ。 ab{3}cならabbbcとマッチする
{m, n} mからn個の繰り返しマッチ。 a{2,4}ならaa, aaa, aaaaとマッチする
(...) 丸括弧中のREとマッチ
[] 文字の集合を指定する。 [amp]なら'a', 'm', 'p'とマッチ。
[0-10]なら0,1,...,10までマッチ。
[^a-d]だとa-d以外
(?=...)   ...に続くものだけマッチする。先読みアサーション(lookahead assertion) Issac(?=Asimov)だと'Issac'に'Asimov'が続く場合だけ'Issac'とマッチする。
(?!...) ...に続くものとマッチしなければマッチする。否定先読みアサーション(negative lookahead assertion) 上の例のIssac(?!Asimov)だとマッチしない。
(?<=...) ...の後から出てくるものとマッチする。
後読みアサーション(lookbehind assertion)
(?<=bar)fooだとbarfooのときマッチ。
(?<!...) 否定後読みアサーション(negative lookbehind assertion)

略記表現

略記法 同等表記 説明
\d [0-9] 数字
\D [^0-9] 非数字
\s [ \f\n\r\t\v] 空白
\S [^ \f\n\r\t\v] 非空白
\w [a-zA-Z0-9_] 単語構成
\W [^a-zA-Z0-9_] 非単語

引用元:http://doc.mas3.net/regexp/

空白, 特殊文字、_, 数字とマッチする.

$ echo csv_test_123_csv.csv | grep -Po '([^\s\w]|_|[0-9])+'
_
_123_
.

例題

行から目的の文字列を抜き出す

sedコマンド;置換や抜き出しができる。
1. sed - E "s/.*(抜き出したい箇所のRE).*/\1/" : \1でキャプチャできる。
2. sed - E "s/置換前の文字列/置換後の文字列/g"

$ echo abcdefg | sed -E 's/.*(d.).*/\1/'
> de

$ echo thee best time to see thee flowers is in thee spring. | sed -E 's/thee/the/g'
> the best time to see the flowers is in the spring

$ echo '<li id="name">apple</li>' | sed -E 's/<[^>]*>//g'
> apple

grepコマンド;一応、行の抜き出しができる。
1. grep - E "RE" : Linux標準の正規表現
2. grep - Po "RE" : Pオプション → PCRE(Perl Compatible Regular Expressions) Perl互換の正規表現、oオプション→ only match text

$ echo value,1.2345cm, ... | grep -Po '(?<=value,)[0-9].*?(?=cm)'
> 1.2345

pythonによる先読み・後読みアサーションの例

import re

# 先読み. 後ろにbarがあるfooとマッチさせたい.
re.search('foo(?=bar)', 'foobar').group(0)
> foo 

# 後読み. 前にabcがあるdefとマッチさせたい.
re.search('(?<=abc)def', 'abcdef').group(0)
> 'def'

# ハイフンに続く単語を探す。(\w は任意のUnicodeにマッチ, [a-zA-Z0-9_]と同じ)
re.search(r'(?<=-)\w+', 'spam-egg').group(0)
> 'egg'

# 否定先読み; eggとマッチしない1文字を抽出(先読みでマッチしないもの)。
re.search(r'.(?!egg)', 'spam-egg').group(0)
> 's'
# 先読みならば'-'がマッチする。

# 上記grepの例。
re.search('(?<=value,)\d.+(?=cm)', "ac, value,1.2345cm,...").group(0)
> '1.2345'

複数とマッチさせるときfindall

次のようなXMLがあったとします。

formula.xml
<Formula>H</Formula> 
<Formula>He</Formula> 
<Formula>Li</Formula> 

単文のみならば、re.searchで良いですが、全てマッチさせたいときは、findallを使います。

import re
data = open(file_name, 'r').read()
re.findall('(?<=Formula>).+(?=\<)', data)
> [ 'H', 'He', 'Li']

マッチオブジェクト

マッチオブジェクトのブール値は常に True である。 match() および search() はマッチがないとき None を返すので、マッチがあるか単純な if 文で判定できる。欠損値を処理できるため、上記よりこちらの方が実用的。

import re
lst=[]
for i in data:
    match = re.search('(?<=Formula>).+(?=\<)', i)
    if(match):
        lst.append(match.group(0))

言語処理100本ノック

http://www.cl.ecei.tohoku.ac.jp/nlp100/
第3章正規表現を一部やってみました。

#!/bin/sh
# 正規表現
wget "http://www.cl.ecei.tohoku.ac.jp/nlp100/data/jawiki-country.json.gz"
gzip jawiki-country.json.gz

# 例題20 JSONデータの読み込み
cat jawiki-country.json | grep -Po '({\"text\":\s\"{{redirect|UK}).+\"title\":\s\"イギリス\"' > uk.json

# 例題21 カテゴリ名を含む行を抽出
cat uk.json | grep -Po '(Category).+]]'

# 例題22 カテゴリ名の抽出
cat uk.json | grep -Po '(?<=Category:).*?(?=[\||\]])'

参考サイト

4
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
7