0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Python の正規表現の re と regex の性能を cProfile で比較

0
Posted at

やりたいこと

Python の正規表現の re と regex とで正規表現のコンパイルとマッチングの性能をプロファイラの cProfile を使って比較する。

regex

インストール

$ pip install regex

regex の使い方

re を regex に置き換えれば regex による正規表現のマッチングを行うことができる。

$ python
>>> import regex
>>> p = regex.compile('def')
>>> p.search('abcdefghi')
regex.Match object; span=(3, 6), match='def'>

cProfile

利用イメージ

cProfile は python の標準のプロファイラでインストールすることなく利用することができる。
cProfile を使うと、関数毎に実行回数、1回あたりの平均実行時間、合計実行時間などを取得することができる。

以下のように計測したい処理の直前で enable() を実行し、計測したい処理の直後で disable() を実行すると
pstats でプロファイル結果を取得することができる。

cProfile の例
import cProfile, pstats, io

pr = cProfile.Profile()
pr.enable()
# 計測したい処理
do_task()
pr.disable()

# 結果出力
s = io.StringIO()
ps = pstats.Stats(pr, stream=s).sort_stats("cumulative")  # or "tottime"
ps.print_stats(50)  # 上位50件を出力
print(s.getvalue())

出力イメージ

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1    0.000    0.000    2.214    2.214 /.../profile.py:46(main)
     1    0.117    0.117    2.214    2.214 /.../profile.py:31(test)
  • ncalls: その関数が呼び出された総回数。
  • tottime: その関数自身の実行に費やされた合計時間(秒)で、その関数内でから呼び出された関数の実行時間は含まない。
  • percall: tottime / ncalls の値で、その関数自身の1回あたりの平均実行時間。
  • cumtime: その関数とその関数が内部で呼び出した全ての関数を含む合計実行時間(秒)。

cProfile による re と regex の比較

プログラム

以下のプログラムで re と regex の比較を行う。

test1.py
import re
import regex
import cProfile, pstats, io

def compile_re(pttrn_str):
    pttrn = re.compile(pttrn_str)
    return pttrn

def compile_regex(pttrn_str):
    pttrn = regex.compile(pttrn_str)
    return pttrn

def search_re(text, pttrn):
    m = pttrn.search(text)
    return m

def search_regex(text, pttrn):
    m = pttrn.search(text)
    return m

def test(num):
    text = 'a' * 1000 + '0' * 1000

    for i in range(0, num):
        pttrn_str = 'a' * 50 + '0' * 50

        pttrn_re = compile_re(pttrn_str)
        search_re(text, pttrn_re)

        pttrn_regex = compile_regex(pttrn_str)
        search_regex(text, pttrn_regex)

def main():
    test(100000)
    return 0

if __name__ == '__main__':
    pr = cProfile.Profile()
    pr.enable()

    # 計測したい処理
    res = main()
    pr.disable

    # 出力
    s = io.StringIO()
    ps = pstats.Stats(pr, stream=s).sort_stats("cumulative") or "tottime"
    ps.print_stats(50)  # 上位50件
    print(s.getvalue())

    exit(res)

実行結果

プログラムの出力結果は以下のようになった。

実行結果(抜粋)
$ python test1.py
         3803513 function calls (3803512 primitive calls) in 2.214 seconds

   Ordered by: cumulative time
   List reduced from 93 to 50 due to restriction <50>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    2.214    2.214 /.../test1.py:46(main)
        1    0.117    0.117    2.214    2.214 /.../test1.py:31(test)
   100000    0.044    0.000    1.441    0.000 /.../test1.py:16(compile_regex) ★
   100000    0.075    0.000    1.397    0.000 /.../lib/python3.12/site-packages/regex/_main.py:349(compile)
   100000    0.323    0.000    1.321    0.000 /.../lib/python3.12/site-packages/regex/_main.py:449(_compile)
   100000    0.035    0.000    0.367    0.000 /.../test1.py:21(search_re)     ★
   100000    0.037    0.000    0.149    0.000 /.../test1.py:11(compile_re)    ★
   100000    0.038    0.000    0.140    0.000 /.../test1.py:26(search_regex)  ★
   200118    0.083    0.000    0.136    0.000 /.../lib/python3.12/enum.py:726(__call__)
   100000    0.034    0.000    0.111    0.000 /.../lib/python3.12/re/__init__.py:226(compile)
   100000    0.049    0.000    0.078    0.000 /.../lib/python3.12/re/__init__.py:280(_compile)
   100000    0.055    0.000    0.055    0.000 /.../lib/python3.12/site-packages/regex/_main.py:471(complain_unused_args)
   200118    0.053    0.000    0.053    0.000 /.../lib/python3.12/enum.py:1129(__new__)

re と regex を比較すると、

  • 正規表現のコンパイル: compile_re と compile_regex を比べると、compile_re の方が実行時間が短く、re の方が性能がよいことがわかる。
  • 正規表現のマッチング: search_re と search_regex を比べると、search_regex の方が実行時間が短く、regex の方が性能がよいことがわかる。

正規表現のコンパイル回数が多く、マッチングの回数が多くない場合には re がよい。
一方、正規表現のコンパイル回数が少なく、マッチングの回数が多い場合には regex がよい。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?