Pythonで辞書のキーに正規表現を使いたいという話

配列や連想配列をディスパッチテーブルとして利用していると、キーに正規表現を使いたくなる事があります。perlだと既にRegexp::Assembleというモジュールを使う方法が書かれていますが、僕はpythonで書きたい訳です。

アプローチは色々ありますが、僕はあくまでディスパッチテーブルとして利用したいので、dictクラスを継承してオレオレ辞書クラスを作ってみる事にしました。で、書いてみたのが以下になります。やたらと短くすんだのでちょっと感動しました。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import re

class regex_dict(dict):
  def __init__(self, items=None):
    for key, val in items.items():
      self.__setitem__(key, val)
  
  def __getitem__(self, item):
    try:
      return super(self.__class__, self).__getitem__(item)
    except:
      for key, val in self.items():
        if isinstance(key, re._pattern_type) and key.match(item):
          return val
      raise KeyError('key not found for %s' % item)

  def __setitem__(self, item_key, item_val):
    try:
      if isinstance(item_key, str):
        item_key = re.compile(item_key)
    except:
      pass
    super(self.__class__, self).__setitem__(item_key, item_val)

このクラスを試しに使ってみると以下のようになります。正規表現にマッチするかどうかで、
ディスパッチ先を変更できていて結構便利なんじゃないかと思います。僕はドメインごとにデータを整理したりと言った用途に使っています。

#!/usr/bin/python
# -*- coding: utf-8 -*-

from regex_dict import regex_dict

rdict = regex_dict({
  u'^[ア-オ]' : 'ア行',
  u'^[カ-コ]' : 'カ行',
  u'^[サ-ソ]' : 'サ行',
  u'^[タ-ト]' : 'タ行',
  u'^[ナ-ノ]' : 'ナ行',
  u'^[ハ-ホ]' : 'ハ行',
  u'^[マ-モ]' : 'マ行',
  u'^[ヤ-ヨ]' : 'ヤ行',
  u'^[ラ-ロ]' : 'ラ行',
  u'^[ワ-ン]' : 'ワ行',
  })
print rdict[u'カナダ']    # カ行
print rdict[u'ニッポン']  # ナ行
print rdict[u'スペイン']  # サ行

え、パフォーマンス?何それ美味いの?

3 thoughts on “Pythonで辞書のキーに正規表現を使いたいという話”

  1. 同じ問題で悩んでいたところ、正にピッタリな記事が投稿されていました。どうもありがとうございます!

  2. それはよかったです!
    pythonもrubyみたいに、組み込みオブジェクトにメソッド追加できたら
    もうちょっと美しいんですけどねー

  3. とてもおもしろい記事ですね。WSGI の実装も、こうあればいいのにと思ってしまいました。
    もちろん、50音順で引ける辞書のためだけに記述したわけではないと思いますが、
    50温順を実現するだけなら、__setitem__ で、インデックスを作成した方がパフォーマンスはよさそうですけど。
    こういう発想は、僕にはなかったです。

Leave a Reply

Your email address will not be published. Required fields are marked *