文字列リストをTRIE Optimizeされた正規表現に
Posted feedbacks - Scheme
共通部分文字列を切り出しながら Trie を作っています。もう少しスマートにできないものかしらん。
出力:
(?:program(?:ist(?:ic)?|m(?:a(?:r|ti(?:c(?:ally)?|st))?|er))?)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | (use srfi-1)
(use srfi-13)
(use gauche.collection)
(define (make-trie strs)
(define (string-ref* s n)
(or (string-null? s) (string-ref s n)))
(define (make-node xs)
(if (null? (cdr xs))
xs
(let ((b (apply min
(pair-fold
(lambda (ys knil)
(if (null? (cdr ys))
knil
(cons (string-prefix-length (car ys) (cadr ys))
knil)))
'() xs))))
(cons (string-take (car xs) b)
(make-trie* (map (cut string-drop <> b) xs))))))
(define (make-trie* ss)
(map make-node (group-collection ss :key (cut string-ref* <> 0))))
(cons "" (make-trie* strs)))
(define (trie->regexp-str tree)
(define (null-node? node)
(and (pair? node)
(string-null? (car node))
(null? (cdr node))))
(if (null? (cdr tree))
(car tree)
(format "~A(?:~A)~A"
(car tree)
(string-join (map trie->regexp-str
(remove null-node? (cdr tree))) "|")
(if (any null-node? (cdr tree)) "?" ""))))
(print (trie->regexp-str
(make-trie '("program"
"programist"
"programistic"
"programma"
"programmar"
"programmatic"
"programmatically"
"programmatist"
"programmer"))))
|


dankogai
#4038()
[
Perl
]
Rating0/2=0.00
これは、実例を見た方が簡単だと思います。 CPANにRegexp::Assembleというモジュールがあるのですが、要はこれの簡易版を作って欲しいということです。私自身、同様のことを行うモジュールを過去にいくつか作っています(e.g Regexp::Optimizer)。
ここでは、文字列のリストを受け取って、それをTRIE化した正規表現に出来ればOKです。Regexp::AssembleやRegexp::Optimizerは正規表現を受け取ってそれをTrie化することも可能ですし、Perl 5.10では内部的にTrie Optimizationを行ったりするのですが、そこまでの機能は求めません。
なお、ここで言う「正規表現」は、必ずしもPerl互換のものである必要はありません。それがTrieになっていることをきちんと示せればOKです。
とはいうものの、Perl5互換になっていた方が、サポートしている環境が多くて有用性は高そうです。可能であればそうして下さい。
Dan the Regexp Assembler
see: Trie (en.wikipedia)
Rating0/2=0.00-0+
[ reply ]