For Gauche 0.9.5


Next: , Previous: , Up: 組み込みライブラリ   [Contents][Index]

6.12 文字列

Builtin Class: <string>

文字列のクラスです。Gaucheでは、文字列は文字のシーケンスともバイトのシーケンスとも みなすことができます。

GaucheではSchemeの文字列は、内部的には、変更不可能なオブジェクト(文字列実体)を 用いて表現されている、ということを強調しておきます。 文字列が変更可能であるR7RSの仕様を満たすために、Schemeレベルの文字列は 文字列実体への間接ポインタとなっています。文字列を変更すると、 変更を反映した新しいstring bodyが作成され、Schemeレベルの文字列が 新しい文字列実体を指すように変更されます。

このことから、文字列操作の性能を見積る場合に注意が必要です。

Gaucheはそもそも文字列の変更に関して全く最適化を行っていません。 (string-set! s k c)は、k番目の文字の前後の部分文字列を取って、 c一文字の文字列を間に挟んで継ぎ足すことで新たな文字列を作るのと 全く同じコストがかかります。 文字列を変更不可として扱う方が良いプログラミングスタイルだと考えるからです。 文字列の作成も参照してください。

R7RSに定義されている文字列操作は非常に限られています。 Gaucheでは追加の組込み手続きのほか、 SRFI-13に定義されている豊富な文字列ライブラリを備えています。 SRFI-13については文字列ライブラリを参照してください。


Next: , Previous: , Up: 文字列   [Contents][Index]

6.12.1 文字列の表記

Reader Syntax: " "

[R7RS+] リテラル文字列です。ダブルクオートの中では、 以下のエスケープシーケンスが認識されます。

\"

[R7RS] ダブルクオート文字

\\

[R7RS] バックスラッシュ文字

\n

[R7RS] 改行文字 (ASCII 0x0a)

\r

[R7RS] 復帰文字 (ASCII 0x0d)

\f

フォームフィード (ASCII 0x0c)

\t

[R7RS] タブ文字 (ASCII 0x09)

\a

[R7RS] アラーム文字 (ASCII 0x07)

\b

[R7RS] バックスペース文字 (ASCII 0x08)

\0

NUL文字 (ASCII 0x00)

\<whitespace>*<newline><whitespace>*

[R7RS] 無視されます。長い文字列リテラルを読みやすさのために折り返す時に便利です。 このエスケープシーケンスはR6RSで導入されました。

\xN;

[R7RS] 16進数Nで表現されたUnicodeコードポイントの文字。 16進数は何桁でも良い。(下の互換性に関する注参照。)

\uNNNN

4桁の16進数NNNNによって示されるUCS2コードを持つ文字。

\UNNNNNNNN

8桁の16進数NNNNNNNNによって示されるUCS4コードを持つ文字。

下はバックスラッシュ-改行エスケープシーケンスの使用例です。

(define *message* "\
  This is a long message \
  in a literal string.")

*message*
  ⇒ "This is a long message in a literal string."

‘message’ の後の空白に注意してください。‘in’の前の空白は読み込みルーチンによって 無視されてしまうので、空白を入れたければ‘message’と続くバックスラッシュの間に 入れる必要があります。もし文字列中に実際に改行文字を入れ、さらにその後の 文字列をインデントさせたい場合は次のようにすると良いでしょう:

(define *message/newline* "\
  This is a long message, \
  \n   with a line break.")

互換性に関する注: 以前は、\xNN (2桁固定の16進数、終端のセミコロン無し) を 文字列中の文字と認識していました。 例えば"\x0d\x0a""\r\n"と同じでした。 互換性のため、終端のセミコロンが見当たらない場合は古い構文もサポートされます。 しかし曖昧な場合もあります。"\x0a;"は新しい構文では "\n"と同じですが、、古い構文では"\n;"となります。

リーダのモードをleagcyにセットすると、常に古い構文で認識されます。 リーダのモードをwarn-legacyにセットすると、 デフォルトと同じように振る舞いますが、古い構文を見つけた場合は警告が出力されます。 詳しくはリーダー字句モードを参照してください。

Reader Syntax: #*" "

不完全な文字列のリテラル表記です。完全な文字列と同様のエスケープシーケンスが 使えます。

#*’ という構文はCommon Lispでビットベクタの表記に使われています。 不完全な文字列は実際はバイトベクタであることから、類似点を認めてこの構文を 採用しました。(もし将来必要になってビットベクタが実装されたとしても、 この構文と共存できます)。


Next: , Previous: , Up: 文字列   [Contents][Index]

6.12.2 文字列に関する述語

Function: string? obj

[R7RS] objが文字列なら#tを、そうでなければ#fを返します。

Function: string-immutable? obj

objが変更不可な文字列なら#tを、そうでなければ#fを返します。

Function: string-incomplete? obj

objが不完全文字列なら#tを、そうでなければ#fを返します。


Next: , Previous: , Up: 文字列   [Contents][Index]

6.12.3 文字列の構築子

Function: make-string k :optional char

[R7RS] 長さkの文字列を作成して返します。 charが与えられればそれで内容を満たします。charが与えられなければ 空白文字で満たされます。常に完全な文字列が返されます。

(make-string 5 #\x) ⇒ "xxxxx"
(make-string 5 #\ふ) ⇒ "ふふふふふ"

make-stringで必要な長さの文字列をアロケートして、string-set! で順番に埋めて行くアルゴリズムは、Gaucheでは極めて非効率であることに 注意してください。そのようなアルゴリズムは、文字列の内部表現とアロケーションメカニズムに 関して不必要な仮定を置いており、Gaucheはその仮定とは合致しません。 文字列の順次作成に適しているのは文字列ポートです (文字列ポート参照)。それが使えない場合、 文字のリストを作成し、list->stringで変換する方がまだmake-stringstring-set!を使うより良いでしょう。

Function: make-byte-string k :optional byte

大きさkの不完全な文字列を作成して返します。 byteが与えられた場合は、その下位1バイトで文字列の各バイトを初期化します。 byteは正確な整数でなければなりません。

Function: string char …

[R7RS] 文字char … から構成された文字列を返します。

Generic Function: x->string obj

文字列への強制型変換手続きです。 objの文字列表現を返します。 デフォルトのメソッドでは、文字列はそのまま返され、数値はnumber->stringで、 シンボルはsymbol->stringで変換され、その他のオブジェクトはdisplay表現 が使われます。

他のクラスはこのメソッドを定義することにより、独自の変換関数を提供することができます。


Next: , Previous: , Up: 文字列   [Contents][Index]

6.12.4 文字列の補間

「文字列の補間(string interpolation)」という用語は、 PerlやPythonなど様々なスクリプト言語で、文字列リテラル内に式を埋め込んでおき 実行時に式を評価した値をそのリテラル内に埋め込む機能を指します。

Schemeはそのような機能を定義していませんが、Gaucheではリーダーマクロを使って 文字列の補間を実装しました。

Reader Syntax: # string-literal

文字列に評価されます。string-literal内に、~expr というシーケンス(ここでexprは有効なScheme式の外部表現)が 現われたら、exprが評価されてその結果がもとの位置に埋め込まれます。 結果の文字列化にはx->stringが使われます(文字列の作成参照)。

チルダと続く式とは、空白文字等を入れずに隣接していなければなりません。 そうでない場合は置換されません。

すぐ後ろに非空白文字が来る場所にチルダ自身を埋め込みたい場合は ~~とします。

それ以外のstring-literal内の文字シーケンスはそのままコピーされます。

Exprに単独の変数を使う場合で、それに続く文字列と変数名を区切りたい 場合は、‘|’文字を使ったシンボルエスケープ構文が使えます。下の例の最後の 2つを見て下さい。

#"This is Gauche, version ~(gauche-version)."
 ⇒ "This is Gauche, version 0.9.5."

#"Date: ~(sys-strftime \"%Y/%m/%d\" (sys-localtime (sys-time)))"
 ⇒ "Date: 2002/02/18"

(let ((a "AAA")
      (b "BBB"))
 #"xxx ~a ~b zzz")
 ⇒ "xxx AAA BBB zzz"

#"123~~456~~789"
 ⇒ "123~456~789"

(let ((n 7)) #"R~|n|RS")
 ⇒ "R7RS"

(let ((x "bar")) #"foo~|x|.")
 ⇒ "foobar"

実は、リーダーはこの構文をマクロ呼び出しへと変換し、それが最終的には string-appendへの呼び出しへと変換されます。

#"This is Gauche, version ~(gauche-version)."
 ≡
(string-append "This is Gauche, version "
               (x->string (gauche-version))
               ".")
Reader Syntax: #` string-literal

これは文字列補間の古い書法です。まだ認識されますが、 新たなコードでは使わないでください。

string-literalの中で、(~expr ではなく) ,expr とマークされた部分のexprが評価されます。 コンマのすぐ次に式を開始する文字がこなければ、コンマはその効力を失います。

#`"This is Gauche, version ,(gauche-version)"

この構文を採用した理由: スクリプト言語の文字列補間構文には様々なバリエーションがありますが、通常、 その言語の他の構文と関連しているものが多いです (例えば、$で変数参照する言語が、$を文字列中の評価部分に前置する等)。

Gaucheの古い形式の文字列補間構文では、準クオートの構文を流用していました (準クオート参照)。準クオートと文字列補間は意味的に似ているからです。 けれども、コンマはそれ自体が文字列中によく出てくる文字なので、少々不格好な仕様でした。

そこで、以下のような理由から、チルダの方がアンクオート文字としてふさわしいと判断しました。

Schemeは他のスクリプト言語より一般的により多くの文字を変数名に使うことが出来ることに注意して下さい。 結果として、変数の値を文字列に挿入する際、ほとんどの場合において変数名を‘|’で区切る 必要があるでしょう。例えば、Perlでは "$year/$month/$day $hour:$minutes:$seconds" と書けたものが、Gaucheでは #`"~|year|/~|month|/~day ~|hour|:~|minutes|:~seconds" と書かねばなりません。 混乱を避けるためには、この構文内では常に直接の変数参照は‘|’で区切るようにしておくのが良いかもしれません。


Next: , Previous: , Up: 文字列   [Contents][Index]

6.12.5 文字列のアクセスと変更

Function: string-length string

[R7RS] 文字列stringの長さ(文字数)を返します。 stringは不完全な文字列であっても構いません。

Function: string-size string

文字列stringの大きさを返します。文字列の大きさは、 stringが占めるメモリ上のバイト数で、これは文字列の内部エンコーディングに 依存します。同じ文字列であっても内部エンコーディングが違えば違う大きさになる場合も あります。

不完全な文字列では、文字列の長さと大きさは常に一致します。

Function: string-ref cstring k :optional fallback

[R7RS+] 完全な文字列cstringk番目の文字を返します。 不完全な文字列を渡すのはエラーです。

kが負数であったりcstringの長さと同じかそれ以上であった場合には エラーが報告されます。但し、引数fallbackが与えられている場合にはエラーを 報告せずfallbackが返されます。これはGaucheの拡張です。

Function: string-byte-ref string k

(多分、不完全な)文字列stringk番目のバイトを返します。 戻り値は、0から255の範囲の整数です。kは0以上、 (string-size string)より小でなければなりません。

Function: string-set! string k char

[R7RS] stringk番目の文字をcharで置き換えます。 kは0以上、(string-length string)より小でなければ なりません。戻り値は未定義です。

stringが不完全文字列の場合、charの下位8ビットの整数値は、 stringk番目のバイトをセットするために使われます。

パフォーマンス上の考慮点について、make-stringの説明を参照して下さい。

Function: string-byte-set! string k byte

stringk番目のバイトを整数byteで置き換えます。 byteは0から255の範囲(255を含む)でなければなりません。 kは0以上、(string-size string)より小である必要があります。 stringが完全文字列の場合、この操作により不完全文字列になります。 戻り値は未定義です。


Next: , Previous: , Up: 文字列   [Contents][Index]

6.12.6 文字列の比較

Function: string=? string1 string2 string3 …

[R7RS] 全ての引数が内容の等しい文字列であれば#tを返します。

Function: string<? string1 string2 string3 …
Function: string<=? string1 string2 string3 …
Function: string>? string1 string2 string3 …
Function: string>=? string1 string2 string3 …

[R7RS] 文字列同士をコードポイントの順序で比較します。全ての引数が順序どおりであれば #tが、そうでなければ#fが返されます。

Function: string-ci=? string1 string2 string3 …
Function: string-ci<? string1 string2 string3 …
Function: string-ci<=? string1 string2 string3 …
Function: string-ci>? string1 string2 string3 …
Function: string-ci>=? string1 string2 string3 …

大文字小文字を無視する文字列比較です。

これらの手続きは、引数に「文字ごとの大文字小文字変換」を適用します。 (変換にはUnicodeの文字単位の大文字小文字マッピングテーブルを使います)。 詳しくはchar-foldcaseの説明を見てください (文字)。 文字ごとの大文字小文字変換は、ドイツ語のエスツェットのような特別な場合を 考慮しません。

(string-ci=? "\u00df" "SS") ⇒ #f

R7RSでは、string-ci*手続きは文字列としての大文字小文字変換を要求しています。 Gaucheは、R7RSに準拠した大文字小文字の違いを無視する比較手続きを gauche.unicodeモジュールに用意しています(Full string case conversion参照)。 R7RSでプログラミングする際に(scheme char)をインポートした場合は、 gauche.unicodeモジュールのstring-ci=?などが使われます。


Next: , Previous: , Up: 文字列   [Contents][Index]

6.12.7 文字列を扱うその他の手続き

Function: substring string start end

[R7RS] stringstart番目の文字(これを含む)から、end番目の文 字(これを含まない)までの部分文字列を返します。引数startおよび endは以下を満さなければなりません。 0 <= start < N0 <= end <= Nstart <= end。ただし、Nは与えられた文字列の長 さです。

startがゼロでかつendNの場合には、stringのコ ピーが返ります。

実は後述する拡張されたstring-copysubstringのスーパーセッ トになっています。この手続きの役割は主にR7RSとの互換性のためです。 シーケンスフレームワークのジェネリック版subseqも参照してください。

Function: string-append string …

[R7RS] string …を連結した内容を含む文字列を新しくアロケートして返 します。

文字列の反転と追加string-concatenateも参照 してください。

Function: string->list string :optional start end
Function: list->string list

[R7RS] 文字列を文字のリストへ、またはその逆の変換をします。

string->listにはオプショナル引数として開始、終了位置のインデッ クスを渡せます。

list->stringではlistの要素はすべて文字でなければなりません。 そうでなければ、エラーシグナルがあがります。文字列や文字がまざったリス トから文字列を構成したい場合には怠惰なテキスト構築にある tree->stringが使えます。

Function: string-copy string :optional start end

[R7RS] stringのコピーを返します。startおよび/あるいはendの 位置インデックスを渡すと元の文字列の部分文字列を取り出せます。 (したがってstring-copyは事実上substringのスーパーセット です)。

start引数のみを与えた場合には、部分文字列はstart番目の文字 (これを含む)からstringの最後までで、それが返ります。 startendの両方を与えたときは、部分文字列はstart番 目の文字(これを含む)から、end番目の文字(これを含まない)までで、 それが返ります。startendが満すべき条件については 前述のsubstringの項を見てください。

註: R7RSの破壊的バージョンstring-copy!srfi-13モジュールで 提供されます (文字列ライブラリ参照)。

Function: string-fill! string char :optional start end

[R7RS] stringchar で埋めます。 オプションの startend は、影響を受ける領域を 制限します。

(string-fill! "orange" #\X)
  ⇒ "XXXXXX"
(string-fill! "orange" #\X 2 4)
  ⇒ "orXXge"
Function: string-join strs :optional delim grammer

[SRFI-13] リスト strs 中にある文字列を、文字列 delim を’糊’ として連結します。

引数 grammer は、文字列がどのように連結されるかを指定する シンボルで、以下のうちの一つです。

infix

それぞれの文字列の間に delim を使います。このモードが デフォルトです。strs が空文字列かヌル文字列を含むリスト である場合は、曖昧に(適当に)動作します。

(string-join '("apple" "mango" "banana") ", ")
  ⇒ "apple, mango, banana"
(string-join '() ":")
  ⇒ ""
(string-join '("") ":")
  ⇒ ""
strict-infix

infix のように動作しますが、strs には空リストは 許されません。したがって、曖昧さはありません。

prefix

delim をそれぞれの文字列の前に補います。

(string-join '("usr" "local" "bin") "/" 'prefix)
  ⇒ "/usr/local/bin"
(string-join '() "/" 'prefix)
  ⇒ ""
(string-join '("") "/" 'prefix)
  ⇒ "/"
suffix

delim をそれぞれの文字列の後ろに補います。

(string-join '("a" "b" "c") "&" 'suffix)
  ⇒ "a&b&c&"
(string-join '() "&" 'suffix)
  ⇒ ""
(string-join '("") "&" 'suffix)
  ⇒ "&"
Function: string-scan string item :optional return
Function: string-scan-right string item :optional return

string から item (文字列あるいは文字)を探します。 string-scanは最も左にある一致を、 string-scan-rightは最も右にある一致を見つけます。

引数 return は、string 中に item が見つかった 場合にどの値が返されるかを指定します。それは以下のシンボルのうちの 一つでなければなりません。

index

item が見つかった場合はstring 内でのインデックス、 そうでなければ #f を返します。これがデフォルトの振る舞いです。

(string-scan "abracadabra" "ada") ⇒ 5
(string-scan "abracadabra" #\c) ⇒ 4
(string-scan "abracadabra" "aba") ⇒ #f
before

item よりも前にある string の部分文字列、あるいは item が見つからなければ #f を返します。

(string-scan "abracadabra" "ada" 'before) ⇒ "abrac"
(string-scan "abracadabra" #\c 'before) ⇒ "abra"
after

item より後ろにある string の部分文字列、あるいは item が見つからなければ #f を返します。

(string-scan "abracadabra" "ada" 'after) ⇒ "bra"
(string-scan "abracadabra" #\c 'after) ⇒ "adabra"
before*

item の前にある string の部分文字列と後ろにある string の部分文字列を返します。item が見つからない場合は、 (values #f #f) を返します。

(string-scan "abracadabra" "ada" 'before*)
  ⇒ "abrac" and "adabra"
(string-scan "abracadabra" #\c 'before*)
  ⇒ "abra" and "cadabra"
after*

string のうち、item の終端までの部分文字列とその残りを 返します。item が見つからなかった場合は、(values #f #f) を返します。

(string-scan "abracadabra" "ada" 'after*)
  ⇒ "abracada" and "bra"
(string-scan "abracadabra" #\c 'after*)
  ⇒ "abrac" and "adabra"
both

string のうち、item の前と item の後ろの 部分文字列を返します。item が見つからない場合、 (values #f #f) を返します。

(string-scan "abracadabra" "ada" 'both)
  ⇒ "abrac" and "bra"
(string-scan "abracadabra" #\c 'both)
  ⇒ "abra" and "adabra"
Function: string-split string splitter &optional limit

stringsplitter で分割し、文字列のリストを返します。 splitter には、文字、文字セット、文字列、正規表現、手続きが 使えます。

splitter が文字の場合、その文字がデリミタとして使われます。

splitter が文字セットの場合は、その文字セットに含まれる文字の 連続がデリミタとして使われます。

splitter に手続きが与えられた場合、string にある各文字に 対してその手続きが呼ばれ、splitter が真の値を返すような連続した 文字群がデリミタとして使われます。

(string-split "/aa/bb//cc" #\/)    ⇒ ("" "aa" "bb" "" "cc")
(string-split "/aa/bb//cc" "/")    ⇒ ("" "aa" "bb" "" "cc")
(string-split "/aa/bb//cc" "//")   ⇒ ("/aa/bb" "cc")
(string-split "/aa/bb//cc" #[/])   ⇒ ("" "aa" "bb" "cc")
(string-split "/aa/bb//cc" #/\/+/) ⇒ ("" "aa" "bb" "cc")
(string-split "/aa/bb//cc" #[\w])  ⇒ ("/" "/" "//" "")
(string-split "/aa/bb//cc" char-alphabetic?) ⇒ ("/" "/" "//" "")

;; some boundary cases
(string-split "abc" #\/) ⇒ ("abc")
(string-split ""    #\/) ⇒ ("")

limit引数が与えられた場合、それは#fか非負整数でなければなりません。 非負整数の場合はsplitterがマッチするデリミタの最大数を指定します。 デリミタがその数だけ見つかったら、残りの文字列は分割されずにそのまま結果に含められます。

(string-split "a.b..c" "." 0)   ⇒ ("a.b..c")
(string-split "a.b..c" "." 1)   ⇒ ("a" "b..c")
(string-split "a.b..c" "." 2)   ⇒ ("a" "b" ".c")

string-tokenize (他の文字列操作) も参照して下さい。


Previous: , Up: 文字列   [Contents][Index]

6.12.8 不完全文字列

Gaucheの内部エンコーディングで正当なマルチバイト文字で構成されていない ようなバイト列を含む文字列は「不完全文字列」となります。

不完全文字列が生成される状況はいくつかあります。たとえば、バイナリデー タを文字列として読み込んだとき、マルチバイト文字の途中で切れた文字列を 読み込んだとき、別の不完全文字列が連結された場合などです。

不完全文字列は例外的な状況であるとみなすべきです。これまではバイト列処 理を使っていましたが、現在はu8vector (ユニフォームベクタ参照)を使うこ とができますので、将来のリリースでは削除する計画です。

万が一、不完全文字列に出会ってしまったら以下の手続を使って完全文字列に 変換することができます。

Function: string-incomplete->complete str :optional handling

不完全文字列strの内容を再解釈して、あらたに完全文字列を返す。 handling引数でstr中の不正なバイト列の扱いかたを指定します。

#f

strが不正なバイト列を含んでいる場合、変換を諦めて#fを返し ます。これがデフォルトのふるまいです。

:omit

不正なバイト列を捨てます。常に完全文字列を返します。

1文字

不正なバイト列中の各バイトを与えた文字で置き換えます。常に完全文字列を 返します。

strが完全文字列なら、そのコピーが返されます。


Previous: , Up: 文字列   [Contents][Index]