HOME もうひとつの Scheme 入門 書き込む

11. 文字、文字列


1. 初めに

今までは主にScheme (Lisp) の考え方について説明しましたが、 データ型については数値とリストを除いて説明していないので、今回から数回にわけて個別のデータ型について説明 していこうと思います。

今回は手始めに文字と文字列について説明します。 ここでの説明は多くの処理系がサポートする R5RS に限っています。

SRFI R6RS で文字列処理は大幅に拡張されています。 また、R6RS では Unicode もサポートされています。 実際にプログラムを書く際には上に挙げたリンクを参照してください。

2. 文字

リテラルとして文字そのものを表すときは文字の前に #\ をつけます。 例えば、a と言う文字を表すときは #\a と書きます。スペース、タブ、ラインフィードやリターンを表すときは #\Space, #\Tab, #\Linefeed, #\Return というように文字の名称で表します。 R5RS で規定されている文字に関する関数には以下のものがあります。
(char? obj)
obj が文字なら真を返します。
(char=? c1 c2)
c1c2 が等しい文字のとき真を返します。
(char->integer c)
c を整数(コード)に変換します。
例:(char->integer #\a) ⇒ 97
(integer->char n)
整数を文字に変換します。
(char<? c1 c2),
(char<=? c1, c2),
(char> c1 c2),
(char>= c1 c2)
文字の大小を比較します。実際には、文字を整数に直してその大小を比較します。
つまり、 (char<? c1 c2)(< (char->integer c1) (char->integer c2)) と等価です。
(char-ci=? c1 c2),
(char-ci<? c1 c2),
(char-ci<=? c1 c2),
(char-ci>? c1 c2),
(char-ci>=? c1 c2)
大文字と小文字を区別しないで文字を比較します。
(char-alphabetic? c),
(char-numeric? c),
(char-whitespace? c),
(char-upper-case? c),
(char-lower-case? c)
それぞれ、c が、アルファベット、数字、空白文字、大文字、小文字のとき真を返します。
(char-upcase c),
(char-downcase c)
それぞれ、c が小文字(大文字)なら 対応する大文字(小文字)を返します。それ以外のときは c をそのまま返します。

3. 文字列

文字列は他の多くの言語と同じようにダブルクォーテンションでくくります。つまり、文字列 abc を 表すには "abc" と書きます。

以下に文字列に関する R5RS で定義されている主な関数を挙げます。

(string? s)
s が文字列なら真を返します。
(make-string n c)
文字 c からなる n 文字の文字列を返します。 c は省略可能。
(string-length s)
文字列 s の長さを返します。
(string=? s1 s2)
文字列 s1, s2 が等しいとき真を返します。
(string-ref s idx)
文字列 sidx 番目の文字を返します。idx は 0 から数えます。
(string-set! s idx c)
文字列 sidx 番目の文字を c にします。
(substring s start end)
文字列 sstart 番目から (end-1) 番目の文字からなる文字列を返します。
(substring "abcdefg" 1 4) ⇒ "bcd"
(string-append s1 s2 ...)
文字列 s1, s2 ... を連結します。
(string->list s)
文字列 s を文字のリストに変換します。
(list->string ls)
文字のリスト ls を文字列に変換します。
(string-copy s)
文字列 s をコピーします。

練習問題

単語の初めを大文字にする関数 title-style を書いてください。
(R6RS には string-titlecase という関数があるので、自分で書く必要はありません。)
> (title-style "yet another scheme tutorial")
"Yet Another Scheme Tutorial"

4. 終わりに

今回は R5RS の範囲で文字と文字列について説明しました。 実際にプログラムを書く際には SRFI R6RS も参照してください。

次回はシンボル型について説明します。シンボル型は Lisp/Scheme に特徴的な データ型で、これを使うと、テキスト処理が高速に行えます。

練習問題の解答

文字列を一度リストに変換してから処理して、また文字列に戻します。
(define (identity x) x)

(define (title-style str)
  (let loop ((ls (string->list str))
	     (w #t)
	     (acc '()))
    (if (null? ls)
	(list->string (reverse acc))
	(let ((c (car ls)))
	  (loop (cdr ls)
		(char-whitespace? c)
		(cons ((if w char-upcase identity) c) acc))))))
> (title-style "the cathedral and the bazaar")
"The Cathedral And The Bazaar"