コンテンツへスキップ

文字列

Stringは、UTF-8文字の変更不可能なシーケンスを表します。

Stringは通常、二重引用符(")で囲まれたUTF-8文字を含む文字列リテラルで作成されます。

"hello world"

エスケープ

バックスラッシュは、文字列内の特殊文字を表し、名前付きエスケープシーケンスまたはUnicodeコードポイントの数値表現のいずれかになります。

使用可能なエスケープシーケンス

"\""                  # double quote
"\\"                  # backslash
"\#"                  # hash character (to escape interpolation)
"\a"                  # alert
"\b"                  # backspace
"\e"                  # escape
"\f"                  # form feed
"\n"                  # newline
"\r"                  # carriage return
"\t"                  # tab
"\v"                  # vertical tab
"\377"                # octal ASCII character
"\xFF"                # hexadecimal ASCII character
"\uFFFF"              # hexadecimal unicode character
"\u{0}".."\u{10FFFF}" # hexadecimal unicode character

バックスラッシュの後に続くその他の文字は、文字自体として解釈されます。

バックスラッシュの後に続く最大3桁の0から7までの数字は、8進数で記述されたコードポイントを表します。

"\101" # => "A"
"\123" # => "S"
"\12"  # => "\n"
"\1"   # string with one character with code point 1

バックスラッシュの後に続くuは、Unicodeコードポイントを表します。これは、Unicodeバイトを表す正確に4つの16進文字(\u0000から\uFFFF)または中括弧で囲まれた1から6個の16進文字の数(\u{0}から\u{10FFFF})のいずれかの後に続くことができます。

"\u0041"    # => "A"
"\u{41}"    # => "A"
"\u{1F52E}" # => "🔮"

1つの中括弧には、空白で区切られた複数のUnicode文字を含めることができます。

"\u{48 45 4C 4C 4F}" # => "HELLO"

補間

補間を含む文字列リテラルを使用すると、実行時に展開される式を文字列に埋め込むことができます。

a = 1
b = 2
"sum: #{a} + #{b} = #{a + b}" # => "sum: 1 + 2 = 3"

String#%でも文字列補間が可能です。

補間セクション内には任意の式を配置できますが、可読性を高めるために式を小さくしておくのが最適です。

バックスラッシュでハッシュ文字(#)をエスケープするか、%q()のような補間しない文字列リテラルを使用することで、補間を無効にできます。

"\#{a + b}"  # => "#{a + b}"
%q(#{a + b}) # => "#{a + b}"

補間はString::Builderを使用して実装され、#{...}で囲まれた各式に対してObject#to_s(IO)を呼び出します。式"sum: #{a} + #{b} = #{a + b}"は次のものと同等です。

String.build do |io|
  io << "sum: "
  io << a
  io << " + "
  io << b
  io << " = "
  io << a + b
end

パーセント文字列リテラル

二重引用符文字列に加えて、Crystalはパーセント記号(%)とデリミタのペアで示される文字列リテラルもサポートしています。有効なデリミタは、括弧()、角括弧[]、中括弧{}、山括弧<>、パイプ||です。パイプを除くすべてのデリミタはネストできます。つまり、文字列内の開始デリミタは次の終了デリミタをエスケープします。

これらは、二重引用符文字列でエスケープする必要がある二重引用符を含む文字列を書くのに便利です。

%(hello ("world")) # => "hello (\"world\")"
%[hello ["world"]] # => "hello [\"world\"]"
%{hello {"world"}} # => "hello {\"world\"}"
%<hello <"world">> # => "hello <\"world\">"
%|hello "world"|   # => "hello \"world\""

%qで示されるリテラルは補間もエスケープも適用されませんが、%Q%と同じ意味を持ちます。

name = "world"
%q(hello \n #{name}) # => "hello \\n \#{name}"
%Q(hello \n #{name}) # => "hello \n world"

パーセント文字列配列リテラル

単一文字列リテラルに加えて、Arrayの文字列を作成するためのパーセントリテラルもあります。これは%wとデリミタのペアで示されます。有効なデリミタはパーセント文字列リテラルと同じです。

%w(foo bar baz)  # => ["foo", "bar", "baz"]
%w(foo\nbar baz) # => ["foo\\nbar", "baz"]
%w(foo(bar) baz) # => ["foo(bar)", "baz"]

%wで示されるリテラルは、スペースを除いて補間もエスケープも適用されません。文字列は単一スペース文字( )で区切られているため、それを文字列の一部として使用するにはエスケープする必要があります。

%w(foo\ bar baz) # => ["foo bar", "baz"]

複数行文字列

任意の文字列リテラルは複数行にまたがることができます。

"hello
      world" # => "hello\n      world"

上記の例では、末尾と先頭のスペース、改行が結果の文字列に含まれています。これを避けるために、複数のリテラルをバックスラッシュで結合して文字列を複数行に分割することができます。

"hello " \
"world, " \
"no newlines" # same as "hello world, no newlines"

あるいは、バックスラッシュの後に改行を文字列リテラル内に挿入することもできます。

"hello \
     world, \
     no newlines" # same as "hello world, no newlines"

この場合、先頭の空白は結果の文字列に含まれません。

Heredoc

ヒアドキュメントまたはheredocは、複数行にわたる文字列を書くのに役立ちます。Heredocは<<-で示され、その後にheredoc識別子が続きます。heredoc識別子は、文字で始まる英数字シーケンスです(アンダースコアを含めることができます)。Heredocは次の行で始まり、heredoc識別子のみを含む次の行で終わります(オプションで空白が前に付きます)。

<<-XML
<parent>
  <child />
</parent>
XML

先頭の空白は、heredoc識別子の前の最後の行の空白の数に従ってheredocの内容から削除されます。

<<-STRING # => "Hello\n  world"
  Hello
    world
  STRING

<<-STRING # => "  Hello\n    world"
    Hello
      world
  STRING

heredoc識別子の後、および同じ行で、その後に続くものは、heredocの前にあった元の式を続けます。heredocの開始識別子の終わりが文字列の終わりであるかのように見えます。ただし、文字列の内容は、独自の行にある必要がある終了heredoc識別子まで、後続の行に表示されます。

<<-STRING.upcase # => "HELLO"
hello
STRING

def upcase(string)
  string.upcase
end

upcase(<<-STRING) # => "HELLO WORLD"
  Hello World
  STRING

同じ行で複数のheredocが開始する場合、それらの本文は順番に読み取られます。

print(<<-FIRST, <<-SECOND) # prints "HelloWorld"
  Hello
  FIRST
  World
  SECOND

Heredocは一般的に補間とエスケープを許可します。

補間またはエスケープなしでheredocを示すには、開始heredoc識別子をシングルクォートで囲みます。

<<-'HERE' # => "hello \\n \#{world}"
  hello \n #{world}
  HERE