Gauche:半角カナ->全角カナ
半角カナから全角カナへの変換
全角から半角への変換とはちょっと違って自明ではない。 濁点や半濁点が不正な位置に存在する可能性があるからだ。 ここでは一案として不正な位置にあるものは濁点や半濁点は無かったものとしてスキップしている。
(use srfi-1)
(use gauche.collection)
(define (make-table src . dst)
(let1 dst (get-optional dst (make-list (string-length src) #t))
(let ((pairs (map cons src dst))
(tbl (make-hash-table)))
(for-each (lambda (kv)
(hash-table-put! tbl (car kv) (cdr kv)))
pairs)
tbl)))
(define (gen-kana-trans . options)
(let-keywords* options ((loseless-voices :voiced #t)
(loseless-semivoices :semivoiced #t))
(let* ((normal (make-table
"アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲンァィゥェォャュョッー、。「」・"
"アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲンァィゥェォャュョッー、。「」・"))
(voiced (make-table
"ウカキクケコサシスセソタチツテトハヒフヘホ"
"ヴガギグゲゴザジズゼゾダヂヅデドバビブベボ"))
(semivoiced (make-table
"ハヒフヘホ"
"パピプペポ"))
(voiced-loseless? (if (string? loseless-voices) #f #t))
(semivoiced-loseless? (if (string? loseless-semivoices) #f #t))
(vs (if voiced-loseless?
(make-hash-table)
(make-table loseless-voices)))
(svs (if semivoiced-loseless?
(make-hash-table)
(make-table loseless-semivoices))))
(lambda (orig-string)
(let lp ((rev-str (reverse (string->list orig-string)))
(result '()))
(if (null? rev-str)
(list->string result)
(let ((c (car rev-str))
(rest (cdr rev-str)))
(cond ((eq? c #?゙) (cond ((null? rest) (if voiced-loseless?
(lp rest (cons #?゛ result))
(lp rest result)))
((hash-table-get voiced (car rest) #f) => (lambda (v) (lp (cdr rest) (cons v result))))
((hash-table-get vs (car rest) voiced-loseless?) (lp rest (cons #?゛ result)))
(else (lp rest result))))
((eq? c #?゚) (cond ((null? rest) (if semivoiced-loseless?
(lp rest (cons #?゜ result))
(lp rest result)))
((hash-table-get semivoiced (car rest) #f) => (lambda (v) (lp (cdr rest) (cons v result))))
((hash-table-get svs (car rest) semivoiced-loseless?) (lp rest (cons #?゜ result)))
(else (lp rest result))))
((hash-table-get normal c #f) => (lambda (v) (lp rest (cons v result))))
(else (lp rest (cons c result)))))))))))
(define kana-trans:half->full (gen-kana-trans))
- Shiro(2006/01/06 19:51:46 PST): 「ア゛」とか書きたいこともあるかもしれないので、 変換できない濁点、半濁点はU+309b, U+309cにマップするという手もあります。
- こんな感じでカスタマイズできるってのはどうでしょう。cut-sea:2006/01/07 05:13:08 PST
(define kana-trans:half->full (gen-kana-trans "アイウエオ" "アイウエオ"))
という風にすると、アイウエオだけは濁点や半濁点を単独で印字するようになります。gosh> (kana-trans:half->full "ア゙イ゙ヴエ゙オ゙ア゚イ゚ウ゚エ゚オ゚ヤユヨラリルレロワヲンァィゥェォャュョッー") "ア゛イ゛ウ゛エ゛オ゛ア゜イ゜ウ゜エ゜オ゜ヤユヨラリルレロワヲンァィゥェォャュョッー" gosh> (kana-trans:half->full "ア゙ーッ") "ア゛ーッ" gosh> (kana-trans:half->full "ヴァルキリー萌え^H^H燃え") "ヴァルキリー萌え^H^H燃え"
それぞれ許容するものを文字列でgen-kana-transの引数に渡すってことで。
- Shiro(2006/01/07 11:22:08 PST): 個人的な好みでは、デフォルトはlosslessが良いと 思うのですが、目的次第でしょうね。それと「ヴ」は全角にありますよ。
- 「ヴ」をvoicedテーブルに追加して、 voiced/semivoicedに#t(正確には文字列以外)を与えると、loselessになる。 もちっとコード整理したいな。cut-sea:2006/01/07 18:16:42 PST
- むーん。どうも文字列って真値になるので、ごちゃごちゃしてきた。 なんかうまいテクがないかな。ロジックも混乱してきた。cut-sea:2006/01/07 19:38:43 PST
- koguro (2006/01/08 03:05:46 PST): gen-kana-transの処理を見ると、(1) 半角文字から全角文字への変換, (2) 文字の合成, (3) カナ表記の妥当性チェック, の3つの処理をまとめて記述していますが、これらは分けて記述した方がよいと思います。Shiroさんが書かれたように(3)の処理は目的により変わることがある(ちなみに"カ゜"といった表記も存在します)のと、(2)の処理についてもUnicodeを使う場合はUnicodeの正規化形式により処理内容が異なる("ガ"をU+30ACとするのかU+30AB U+309Bとするのかが変わってくる)のでカスタマイズできた方が望ましいためです。
- えんどう(2006/01/08 06:20:26 PST)単に「ミニsed」みたいなのを書くんじゃだめでしょうか?とりあえずsとyが書ければ便利と思います。
- Shiro(2006/01/08 10:26:03 PST): いろいろ解き方はあると思います
- 遅くてもいいからさくっと書きたい → GaucheRefj:regexp-replace-all*あたりが 使えるのでは。
- ばりばりに速いのが欲しい → DFAを組むのがよろしいでしょう。