text.tr
- 文字変換 ¶このモジュールは、入力ストリームから指定の文字を置き換えて出力する、
文字変換(transliterate)機能を提供します。
Unixのtr(1)
コマンドで実装され、sed
やperl
にも
採り入れられている機能です。
Gaucheのtr
はマルチバイト文字/文字列を正しく扱います。
{text.tr
}
inputから文字を読み込み、その文字がfrom-list内にあれば
対応するto-list内の文字に置き換えて、outputへと書き出します。
from-listに無い文字はそのままoutputへと渡されます。
inputとoutputの既定値はそれぞれ現在の入力ポートと 出力ポートです。
from-listとto-listは文字列でなければなりません。 その中には次のような表記を使うことができます。それ以外の文字はそのまま使われます。
x-y
文字x
から文字y
までの文字の昇順の並びと解釈されます。
x
とy
は含まれます。文字の並びはGaucheの内部文字エンコーディングに
よって決定されるので、一般にはx
とy
は同じキャラクタクラスの中に
止めておいた方が安全でしょう。x
はy
より小さくなければなりません。
x*n
文字x
のn
個の並び。n
は10進数で表記された数値です。
これはto-listでのみ有効で、from-listで使うとエラーになります。
n
が省略されるか0の場合、x
はto-listの長さがfrom-list
の長さに達するまで繰り返されます(その場合、to-listの残りは無視されます)。
\
x
文字x
それ自身。特殊文字そのものを埋め込みたい場合に使います。
文字列のリーダも\
を解釈するので、\\
と書かねばならないことに注意
して下さい。
グラフィカルでない文字のための構文はありません。文字列リーダの構文を使って そのような文字を文字列に含めることができます。
いくつか例を挙げます。
;; 大文字と小文字を交換します (tr "A-Za-z" "a-zA-Z") ;; ひらがなとかたかなを交換します (tr "ぁ-んァ-ン" "ァ-ンぁ-ん") ;; 7ビットのノングラフィカルな文字を‘?’に変換します (tr "\x00-\x19\x7f" "?*")
from-listに文字の重複があった場合、最初の出現位置との対応が使われ、 以降の同じ文字の対応は無視されます。
(string-tr "abc" "aabbcc" "123456") ⇒ "135"
to-listがfrom-listより短い場合、動作はキーワード引数deleteに 依存します。もし真の値がdeleteに与えられれば、from-listに現われて to-listに対応するものがない文字は入力から取り除かれます。そうでなければ そのような文字はそのまま出力されます。
(string-tr "abracadabra" "abc" "" :delete #t) ⇒ "rdr"
真の値がcomplementに与えられた場合、from-listの文字の
補集合がfrom-listとして使われます。この文字集合は極めて大きくなる
可能性があることに注意してください。従って、一般にこのオプションは
to-listに‘*’を使ってそれらの文字を一文字にマッピングするか、
delete
オプションと併用するかしないとあまり意味がありません。
真の値がsqueezeに与えられた場合、同じ文字への置換が2つ以上並ぶ場合に 2つめ以降の文字が削除されます。to-listが空の場合は、from-list に含まれる文字で同一文字が並んだ場合に2つめ以降の文字が削除されます。
内部的に、tr
はキャラクタのマッピングのためにテーブルを使用します。
但し、Gaucheでは極めて大きな文字集合を扱うため、テーブルはキャラクタコードの
小さい文字のみに対して使われます(デフォルトではコード255以下の文字)。
もし、より大きな文字を頻繁に変換することが分かっていて、メモリを余分に使っても
速度を上げたい場合は、このテーブルの大きさをtable-sizeキーワード引数で
指定することができます。例えばEUC-JPコードで大量の平仮名と片仮名を変換する場合は、
table-sizeを42483以上にすると、全ての変換がテーブルルックアップで
行われます。
tr
が変換テーブルを計算するのにいくらかオーバーヘッドがあることに
注意して下さい。内側のループでtr
を繰り返し呼ぶような場合は
下に示すbuild-transliterator
を使った方が良いでしょう。
{text.tr
}
入力をstringから取って変換結果を文字列で返す以外はtr
と同じです。
{text.tr
}
実際の変換動作をする手続きを作成して返します。内部データのセットアップを済ませるため、
同じ文字変換セットに対してtr
を繰り返し呼ぶような場合は、この手続きを用いることで
初期化のオーバヘッドを軽減することができます。
註記:inputやoutputキーワード引数が省略された場合、 作成される変換手続きは、それが使用された時点でのカレント入出力ポート を参照します。
(with-input-from-file "huge-file.txt"
(lambda ()
(let loop ((line (read-line)))
(unless (eof-object? line) (tr "A-Za-z" "a-zA-Z")))))
;; 以下の方が効率良く動作します...
(with-input-from-file "huge-file.txt"
(lambda ()
(let ((ptr (build-transliterator "A-Za-z" "a-zA-Z")))
(let loop ((line (read-line)))
(unless (eof-object? line) (ptr))))))