pythonで正規表現を扱う際に、コンパイルする例を紹介します。
事前にコンパイルをしておくことで、その分のオーバーヘッドを短縮することができます。
例えば、ループ内で正規表現検索をする場合、毎回コンパイルするのと事前にコンパイルしておくのを比べると、後者の方が早いです。
ただし、単発で正規表現チェックをする場合は、コンパイルをしても全体の実行速度はそこまで早くなりません。
正規表現をコンパイルするサンプル
import re # 正規表現をコンパイル pattern = r'\[\d{1,}\]' re_pattern = re.compile(pattern) # 変換前 val = '[12345]abcdefg' print(val) # 変換後 result = re_pattern.sub('', val) print(result)
[12345]abcdefg # 変換前 abcdefg # 変換後
正規表現をコンパイルすべきタイミングについて
記事冒頭でも少し触れていますが、単発で使用するような場合は、正規表現をコンパイルする必要はありません。
以下のような場合は、コンパイルしても1回しか使用されないので、性能の向上はほとんど見られません。
import re # 正規表現をコンパイル pattern = r'\[\d{1,}\]' re_pattern = re.compile(pattern) # 正規表現で変換(1回しか使われない) result = re_pattern.sub('', '[12345]abcdefg') print(result)
一方、以下のようにループの中で何度も参照されるような場合は、コンパイルするメリットがあります。
# 正規表現のコンパイル実行 pattern = r'\[\d{1,}\]' re_pattern = re.compile(pattern) # ループ for(int i = 0; i < 100000; i++) # 正規表現で変換(ループ中で何回も使用される) result = re_pattern.sub('', '[12345]abcdefg') print(result)
具体的な性能向上については、以下のような検証結果があります。
実行速度の比較・コンパイル無し
~$ for x in 1 10 100 1000 10000 100000 1000000; do python -m timeit -n $x -s 'import re' 're.match("[0-9]{3}-[0-9]{3}-[0-9]{4}", "123-123-1234")'; done
1 loops, best of 3: 3.1 usec per loop
10 loops, best of 3: 2.41 usec per loop
100 loops, best of 3: 2.24 usec per loop
1000 loops, best of 3: 2.21 usec per loop
10000 loops, best of 3: 2.23 usec per loop
100000 loops, best of 3: 2.24 usec per loop
1000000 loops, best of 3: 2.31 usec per loop・コンパイルあり
~$ for x in 1 10 100 1000 10000 100000 1000000; do python -m timeit -n $x -s 'import re' 'r = re.compile("[0-9]{3}-[0-9]{3}-[0-9]{4}")' 'r.match("123-123-1234")'; done
1 loops, best of 3: 1.91 usec per loop
10 loops, best of 3: 0.691 usec per loop
100 loops, best of 3: 0.701 usec per loop
1000 loops, best of 3: 0.684 usec per loop
10000 loops, best of 3: 0.682 usec per loop
100000 loops, best of 3: 0.694 usec per loop
1000000 loops, best of 3: 0.702 usec per loop
従って、同じ正規表現をループなどで使い回す時は、コンパイルした方が実行速度は早くなるようです。