正規表現では基本的に括弧は扱えないわけですが, 別に全く認識できないというわけではなくて, 任意のn回ネストした括弧が認識できないというだけです. つまり, {w | w = anbn, n ∊自然数}みたいな言語のクラスが認識できません.
"((( ... ((( ))) ... )))"みたいな言語や"(( ... ) ( ... ))"のような言語(いずれも左右の括弧が正しく対応している場合). しかし, 1回ネストしているとか, 2回ネストしているとか, 有限回ネストしている括弧だけの認識なら, 必ずしも不可能ではありません. しかも, かなりイディオム的に記述可能です.
Clojure(Java)の正規表現でルビ部分を認識する正規表現は,
《[^》]*》
と書けます. 最初に開く括弧(《)を認識し, 閉じ括弧以外([^》]*)の文字からなる文字列を受け付けて, 閉じ括弧(》)が来たら, 括弧全体を認識するといった感じ.
余談ですが, 二回ネストしている括弧を認識する場合は, 以下のような感じになります.
《([^《^》]|(《[^》]*》))*》
一重の括弧を認識する正規表現の中にもう一つ別の括弧を認識する正規表現(青い部分)が入っている感じです. 外側の開閉括弧間の文字列は, ([^《^》]|(《[^》]*》))*で認識します. 三重括弧の場合は, [^》]*の中を拡張して, ([^《^》]|(《[^》]*》))*で書き換えれば, 三重括弧が認識できる要領になります.
こんな感じで, スタックに積むように, 正規表現を伸ばしていけば, 有限回ネストする括弧の認識を正規表現で書くことができます.
以下が実行例. 括弧(《》)の部分をparに書き換えます. 上から順に, 1重の括弧の認識, 1重の括弧の失敗例, 2重括弧の認識, 3重括弧の認識例です.
user> (clojure.string/replace "《some》 text 《》 here" #"(《[^》]*》)" "par") "par text par here" user> (clojure.string/replace "《《text》》 《》" #"《[^》]*》" "par") "par》 par" user> (clojure.string/replace "《《text》 abc 《text》》 《text》 《》" #"《([^《^》]|(《([^《^》]|(《[^》]*》))*》))*》" "[]") "[] [] []" user> (clojure.string/replace "《《text》 abc 《text》》 《《text》 abc 《text《》》》 《text》 《》" #"《([^《^》]|(《([^《^》]|(《[^》]*》))*》))*》" "[]") "[] [] [] []"というわけで, 青空文庫のテキストからルビとコメント[#……], バー(|), 本文と関係ない部分を取り除くプログラム.
(use '[leiningen.exec :only (deps)]) (def top-bar (re-pattern (apply str (take 55 (cycle "-"))))) (defn remove-top&bot [text] (first (clojure.string/split (nth (clojure.string/split text top-bar) 2) #"\n\r\n\r\n\r\n"))) (defn remove-pars [text] (clojure.string/replace text #"||(《[^》]*》)|([[^]]*])" "")) (defn file-in-out [trim-fn file-name] (let [target-text (slurp file-name :encoding "shift-jis") new-file-name (str file-name ".rr.txt")] (println (trim-fn target-text)))) (file-in-out #(remove-pars (remove-top&bot %)) (second *command-line-args*))shift-jisなのでslurpで, エンコードの指定をする必要があります. また, 本文に関係ない部分のテキストもカットしてあります.
C:\aozora>lein exec removepars.clj 夏目漱石//道草.txt > 道草nopar.txtのようにして使います.
0 件のコメント :
コメントを投稿