For Gauche 0.9.10


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

6.11 文字列

Builtin Class: <string>

文字列のクラスです。

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.11.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;"となります。

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


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

6.11.2 文字列についての述語

Function: string? obj

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

Function: string-immutable? obj

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

文字列リテラルおよび、symbol->stringなどいくつかの手続きから 返される文字列は変更不可です。プログラム中で変更不可の文字列を確実に手に入れたい場合は string-copy-immutableが使えます。

Function: string-incomplete? obj

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


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

6.11.3 文字列の構築子

Function: make-string k :optional char

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

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

make-stringで必要な長さの文字列をアロケートして、string-set! で順番に埋めて行くアルゴリズムは、Gaucheでは極めて非効率であることに 注意してください。

Gaucheの文字列オブジェクトは、変更不可能な文字列本体への単なるポインタです。 string-set!等の文字列を破壊的変更する操作は、 実際には変更箇所以外は元の文字列本体をコピーした新たな文字列本体をアロケートして、 元の文字列オブジェクトのポインタを差し替えるこようになっています。 従って、文字列のコピーを作るのと同等の効率となります。

文字列の順次作成に適しているのは文字列ポートです (文字列ポート参照)。それが使えない場合、 文字のリストを作成し、list->stringで変換する方がまだmake-stringstring-set!を使うより良いでしょう。

Function: make-byte-string k :optional byte

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

Function: string char …

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

Generic Function: x->string obj

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

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


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

6.11.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.10."

#"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-interpolate* ("This is Gauche, version "
                      (gauche-version)
                      "."))

;; then, it expands to...

(string-append "This is Gauche, version "
               (x->string (gauche-version))
               ".")

(註: string-interpolate*の厳密な仕様は将来変わるかもしれないので、 現在の振る舞いに依存したコードは避けて下さい。)

#"..."構文はマクロstring-interpolate*の呼び出しと等価なので、 この構文を使う際にはGaucheモジュールのstring-interpolate*が 見えている必要があります。Gaucheコードを書く場合、Gaucheモジュールはデフォルトで 継承されているので、普通は気にする必要はありません。R7RSコードから始めて #"..."構文を使いたくなった場合は、(import (gauche base))等で string-interpolate*を見えるようにしてください。 また、ローカルにstring-interpolate*をシャドウしないように気をつけてください。

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.11.5 文字列カーソル

文字列カーソルは文字列の中の文字を指示するオブジェクトです。文字列中の文字を指定するのに インデックスも使えますが、カーソルの方が効率が良いです。例えば、 文字インデックスを使ってマルチバイト文字列中の文字をstring-refで取り出すには、 Gaucheは文字列の最初からその文字まで文字列をたどらなければならず、 インデックスnに対してO(n)かかります。カーソルを使えばO(1)でアクセスできます (ASCII文字だけからなる文字列や、索引付加済み文字列では 文字インデックスを使ったアクセスもO(1)になります。 索引付加済み文字列については文字列索引を参照してください。)

長さnの文字列には、n+1個のカーソルが存在し得ます。 一番最後のカーソルは文字列末尾を指し、該当する文字を持ちません。 探している文字が無いことを示す値としても使われます。

文字列カーソルは特定の文字列と結びついていて、それ以外の文字列に対して使うのは無効です。 また、元の文字列が変更されると文字列カーソルは無効になります。 ただ、無効になったカーソルを使っても必ずしもエラーになるとは限りません。 gosh-fsafe-string-cursorsオプションつきで起動すると、 性能が落ちますがその種のエラーを検出することができます。 詳しくはGaucheを起動するを参照してください。

ほとんどの場合、文字列カーソルはヒープアロケーションを伴いません。 文字列カーソルがヒープにアロケートされるのは (1)巨大なバイトインデックスを指す場合か、 (2)-fsafe-string-cursorsを使って追加の実行時検査を有効にした場合です。

現在の実装では、カーソルがヒープアロケートされる閾値は、64bitシステムでは 2^56、32bitシステムでは2^24です。 64bitシステムでこの閾値を越えることは現実的にはありえないでしょう。 32bitシステムでは、超巨大な文字列オブジェクトを使った場合にあり得るかもしれませんが、 それほど大きなデータを扱うならば、 単一の文字列ではなくデータ構造を工夫した方が良いかもしれません。

文字インデックスを取るGaucheの文字列手続きのほとんどはカーソルも受け付けます。 但し、それに依存したコードは移植性がありません。例えばsubstringは、 Gauche版ではインデックスもカーソルも使えますが、RnRSではインデックスしか許していません。 移植性のあるプログラムを書く際には、srfi-130モジュールにある手続きでのみ カーソルを使うようにしてください (Cursor-based string library参照)。

Builtin Class: <string-cursor>

文字列カーソルのクラスです。書き出される時に表示される数字は、 文字インデックスではなく文字へのバイトオフセットです。

(string-index->cursor "あかさたな" 2)
 ⇒ #<string-cursor 6>
Function: string-cursor? obj

[SRFI-130] objが文字列カーソルなら#tを、そうでなければ#fを返します。

Function: string-cursor-start str

[SRFI-130] 文字列strの先頭を指す文字列カーソルを返します。 strが空文字列でも有効な文字列カーソルが返されます。 (strが空文字列の場合、string-cursor-endが返すカーソルは 同じものです)。

Function: string-cursor-end str

[SRFI-130] 文字列strの末尾(最後の文字の直後)を指す文字列カーソルを返します。 strが空文字列の場合、string-cursor-startが返すカーソルと 同じものが返されます。 このカーソルは有効な文字を指しません。

Function: string-cursor-next str cur

[SRFI-130] 文字列str中で、curが指す文字の次を指すカーソルを返します。 curに文字インデックスを渡すこともできます。curが文字列末尾を 指している場合はエラーが投げられます。

Function: string-cursor-prev str cur

[SRFI-130] 文字列str中で、curが指す文字の一つ前を指すカーソルを返します。 curには文字インデックスを渡すこともできます。curが文字列先頭を 指している場合はエラーが投げられます。

Function: string-cursor-forward str cur n

[SRFI-130] 文字列str中で、カーソルcurが指す文字からn文字先を指す カーソルを返します。curに文字インデックスを渡すこともできます。

Function: string-cursor-back str cur n

[SRFI-130] 文字列str中で、カーソルcurが指す文字からn文字前を指す カーソルを返します。curに文字インデックスを渡すこともできます。

Function: string-index->cursor str index

[SRFI-130] 文字列インデックスindexをカーソルに変換します。 indexが既にカーソルであった場合はそれがそのまま返されます。

Function: string-cursor->index str cur

[SRFI-130] 文字列カーソルcurをインデックスに変換します。 curが既にインデックスであった場合はそれをそのまま返します。

Function: string-cursor-diff str start end

[SRFI-130] 二つの文字列カーソルstartendの間にある文字数を返します。 startよりendが後を指していれば結果は正に、 endstartより手前にあれば結果は負になります。 startendは文字インデックスであっても構いません。

Function: string-cursor=? cur1 cur2
Function: string-cursor<? cur1 cur2
Function: string-cursor<=? cur1 cur2
Function: string-cursor>? cur1 cur2
Function: string-cursor>=? cur1 cur2

[SRFI-130] 二つの文字列カーソル、もしくは二つのインデックスの前後関係を比較します (カーソルとインデックスは比較できません)。


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

6.11.6 文字列索引

Gaucheは文字列をマルチバイト形式で保持しているので、 デフォルトではランダムアクセスにO(N)の時間がかかります。 ほとんどの場合、文字列へのアクセスは最初から順に見て行くか、 検索してマッチした箇所を見るかで、Gaucheはそれらの操作をプリミティブで提供しているので、 文字列を文字のインデックスでアクセスする必要は滅多にないでしょう。 けれどもどうしても文字列をランダムにアクセスしたい場合があるかもしれません (サードパーティ製のライブラリの移植、などが考えられます)。

O(1)ランダムアクセスを実現する方法は二つばかりあります。

一つは、文字へのインデックスのかわりに、 文字列カーソルを使うことです(文字列カーソル参照)。 文字列カーソルはsrfi-130で定義され、srfi-130のインタフェースを使っている コードはそのまま、効率的に動きます。ただ、もし外部に向けたインタフェースが 文字インデックスを要求していたなら、カーソルとインデックス間の相互変換のところで O(N)時間がかかってしまいます。

もう一つの方法は、文字のインデックスとマルチバイト文字列内の位置を表す 文字列索引をあらかじめ計算しておくことです。計算時にはO(N)の時間・空間 コストがかかりますが、一度計算すれば以降はO(1)でランダムアクセスできます。 (実際には、文字列の長さに応じて16から256文字ごとに位置を記録するので、 文字列本体に比べて索引はそれほどメモリを取りません)。

srfi-135 (変更不可なテキスト) はO(1)アクセス可能な文字列を「テキスト」という型で 扱っています。Gaucheでは、テキストは単に文字列索引つきの変更不可な文字列です。

Function: string-build-index! str

文字列strの索引を計算して、str自身を返します。 この操作はstr自体の内容を変えるものではないため、変更不可な文字列にも適用できます。

strがシングルバイト文字列(ASCIIのみからなるか、不完全な文字列)の場合、 あるいは短い(64バイト以下)の場合、索引は実際には計算されません。 また、既に索引がある文字列を渡しても構いません。その場合、単に索引の計算はスキップされます。

索引は文字列の内容そのものに対してつけられます。strの内容をstring-set!などで 置き換えた際には、索引は破棄されます。

Function: string-fast-indexable? str

文字列strへの文字インデックスでのアクセスがO(1)で行える場合に#tを、 そうでなければ#fを返します。 #tが返されるのは、strがシングルバイト文字列か、 短い文字列か、文字列索引が付加された長い文字列である場合です。


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

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

Function: string-length string

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

Function: string-size string

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

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

Function: string-ref cstring k :optional fallback

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

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

cstringがマルチバイト文字列でインデックスが付加されていない場合、 この手続きはO(k)時間かかります。O(1)アクセスを得る方法は 文字列索引を参照してください。

kに文字列カーソルを渡すこともできます (これもGaucheの拡張です)。 カーソルによるアクセスはO(1)です。

Function: string-byte-ref string k

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

Function: string-set! string k char

[R7RS base] 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.11.8 文字列の色々な比較

Function: string=? string1 string2 string3 …

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

もし引数に不完全文字列がひとつでもある場合、 全ての文字列が不完全でありかつ内容が同じである場合に限り#tが返ります。 言い換えれば、完全な文字列と不完全な文字列は決して等しくなりません。

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

[R7RS base] 文字列同士をコードポイントの順序で比較します。全ての引数が順序どおりであれば #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モジュールに用意しています(フルセットの大文字小文字変換参照)。 R7RSでプログラミングする際に(scheme char)をインポートした場合は、 gauche.unicodeモジュールのstring-ci=?などが使われます。


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

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

Function: substring string start end

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

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

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

Function: string-append string …

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

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

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

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

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

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

Function: string-copy string :optional start end

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

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

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

Function: string-copy-immutable string :optional start end

stringが変更不可であればそれをそのまま返し、変更可能であれば 変更不可なコピーを返します。 string-copyが常に変更可能なコピーを返すのと対照的です。

startendは非負整数の文字インデックスか文字列カーソルで、 string中のコピーされる範囲を指定します。

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

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

(string-fill! "orange" #\X)
  ⇒ "XXXXXX"
(string-fill! "orange" #\X 2 4)
  ⇒ "orXXge"

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

Function: string-join strs :optional delim grammar

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

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

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 grammar limit start end
Function: string-split string splitter :optional limit start end

[SRFI-152+] stringsplitter で分割し、文字列のリストを返します。 splitter には、文字、文字集合、文字列、正規表現、手続きが 使えます。

splitter が文字か文字列の場合、それがそのままデリミタとして使われます。 なお、srfi-152のstring-splitはデリミタとして文字列しか許しません。 (また、省略可能引数の最初のものは常にgrammarとして扱われます。 後述する互換性への註を参照)。

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 ""    #\/) ⇒ ("")

grammar引数の意味は上のstring-joinと同じです。 シンボルinfixstrict-infixprefixsuffixのいずれかでなければなりません。 省略時はinfixが指定されたのと同じです。

(string-split "/a/b/c/" "/" 'infix)  ⇒ ("" "a" "b" "c" "")
(string-split "/a/b/c/" "/" 'prefix) ⇒ ("a" "b" "c" "")
(string-split "/a/b/c/" "/" 'suffix) ⇒ ("" "a" "b" "c")

一般的に、以下の関係が成り立ちます。

(string-join XS DELIM GRAMMAR) ⇒ S
(string-split S DELIM GRAMMAR) ⇒ XS

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

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

互換性への註: grammar引数はsrfi-130およびsrfi-152(文字列ライブラリ(簡略版)参照) との一貫性のために追加されました。 しかし、互換性および簡便性のため、grammarを省略してlimitを与えることも できます。grammarはシンボルでlimitは整数なので判別可能です。 srfi-152と互換性のあるコードを書く場合はgrammar引数を取る最初の形式を使ってください。

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

startend引数は分割する前に入力文字列を指定の範囲に制限します。

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

Function: string-map proc str str2 …
Function: string-map proc str :optional start end

[R7RS base][SRFI-13] 入力文字列中の各文字に対してprocを適用し、その結果の文字を集めた 文字列を返します。procは文字を返さねばなりません。

歴史的経緯により、この手続きは2種類のインタフェースを持ちます。 最初のインタフェースは1個以上の文字列を取ります。 procには文字列引数の数だけ、各文字列から取られた文字が渡されます。 繰り返しは最も短い文字列でストップします。これはR7RS-smallで定義され、 mapvector-map等と一貫性があります。

二番目のインタフェースでは、文字列引数はひとつだけで、省略可能なstart/end 引数を取ります。startendは非負整数のインデックスか 文字列カーソルで、入力文字列を使う範囲を制限します。

procが適用される順序は左から右とは限りません。順序に依存しないようにしてください。

procが継続を補足し、それが再び起動された場合、既にstring-mapから 返された結果は影響を受けません。(R7RSで指定されています)

(string-map char-upcate "apple") ⇒ "APPLE"
(string-map (^[a b] (if (char>? a b) a b)) "orange" "apple") ⇒ "orpng"
(string-map char-upcase "pineapple" 0 4) ⇒ "PINE"
Function: string-for-each proc str str2 …
Function: string-for-each proc str :optional start end

[R7RS base][SRFI-13] procを入力文字列の各文字に左から右の順で適用します。procの結果は捨てられます。

歴史的経緯から、この手続きは2種類のインタフェースを持ちます。 最初のインタフェースはR7RSで、二番目のインタフェースはsrfi-13で定義されています。 詳しくは上のstring-mapの項を参照してください。


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

6.11.10 不完全文字列

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

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

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

万が一、不完全文字列に出会ってしまったら string-incomplete->completeで完全な文字列に変換することができます。

Reader Syntax: #**""

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

#* という構文はCommon Lispでビットベクタの表記に使われています。 不完全な文字列は実際はバイトベクタであることから、類似点を認めてこの構文を 採用しました。

註: 0.9.9までは、不完全文字列リテラルとして#*"..."を使っていました。 しかし、それはビットベクタリテラルと共存できないことが判明しました。 #*は有効なビットベクタリテラル(長さ0のビットベクタ)で、 また"はデリミタなので、#*"...."は長さ0のビットベクタと 通常の文字列、とパーズできてしまいます。 0.9.10からは、不完全文字列リテラルは#**"..."になりました。 ちょっと長いですが、もともと不完全文字列は例外的に現れるもので、 積極的に使うべきではありません。

後方互換性のため、デフォルトでは#*"..."はリーダー字句モードが strict-r7でない限りは不完全文字列リテラルとして読まれます。 (リーダー字句モードについてはリーダー字句モード参照。) リーダ字句モードがwarn-legacyだった場合は、 このリテラルは不完全文字列として読まれますが、警告が出されます。 リーダ字句モードがstrict-r7であれば、 このリテラルは長さ0のビットベクタと、通常の文字列として読まれます。

将来のリリースでは、デフォルトで#*"..."は警告を出すようにし、 その後strict-r7の振る舞いに移行する予定です。

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

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

#f

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

:omit

不正なバイト列を捨てます。

1文字

不正なバイト列中の各バイトを、filler引数に与えられ文字で置き換えます。 filler引数のデフォルトは?です。

:escape

Replace each byte in illegal byte sequences by a sequence of filler <hexdigit> <hexdigit>. Besides, the filler characters in the original string is replaced with filler filler.

1文字

不正なバイト列中の各バイトを、filler <hexdigit> <hexdigit> の3文字で置き換えます。さらに、元文字列中にfillerが登場した場合はそれぞれを filler filler で置き換えます。

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

この手続きは、handling引数が#f (デフォルト) で入力が 不完全文字列だった場合に#fを返す以外は、常に完全文字列を返します。

Gaucheの内部エンコーディングがutf-8であれば、この手続きは次のとおり動作します。

(string-incomplete->complete #*"_abc")
  ⇒ "_abc"     ; can be represented as a complete string

(string-incomplete->complete #*"_ab\x80;c")
  ⇒ #f        ; can't be represented as a complete string

(string-incomplete->complete #*"_ab\x80;c" :omit)
  ⇒ "_abc"     ; omit the illegal bytes

(string-incomplete->complete #*"_ab\x80;c" :replace #\_)
  ⇒ "_ab_c"    ; replace the illegal bytes

(string-incomplete->complete #*"_ab\x80;c" :escape #\_)
  ⇒ "__ab_80c" ; escape the illegal bytes and escape char itself

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