ヒアドキュメント / 複数行文字列

改行を含むテキストをソースコードの中で普通に複数行で書いて、それを文字列として処理させる、各プログラミング言語ごとの方法のメモ。

ヒアドキュメントとか複数行文字列と呼んだりする。

改行だけでなくタブなど、普通であればエスケープ処理をしないといけないコントロール文字もそのまま書ける。

中に変数の参照を書くことにより普通の文字列リテラルと同様に変数展開される言語(Ruby, Perl, シェルスクリプトなど)もある。

C言語 C++ Java Scala Groovy PHP Python Ruby Perl sh JavaScript

スポンサーリンク

C言語, C++

ない。と思っていたけど、C++11には Raw String Literal というのがあるらしい。

Java

ない。

Scala

ダブルクオーテーション3つ連続で複数行文字列を書くことができる。

エスケープ処理をせずに改行やダブルクオーテーションなどを含めることができる。ダブルクオーテーション3つ連続は、終端記号になってしまうので、ヒアドキュメントの中にダブルクオーテーション3つ連続は、たぶん含められない。

val str = """foo
bar""";

Groovy

シングルクオーテーションまたはダブルクオーテーション3つ連続で複数行文字列を書くことができる。

シングルクオーテーション3つ連続とダブルクオーテーション3つ連続の両方が含まれる文字列はどうやって書くんだろう?

PHP

$str = <<<EOS
foo
bar
EOS;

普通のヒアドキュメントとNowdocというものがある。ヒアドキュメントでは、" で囲んだ文字列リテラルと同じように、$ で始まる部分が変数名としてその値に インライン展開されるのに対して、 Nowdocは、' で囲んだ文字列リテラルと同じように、そういった展開がされない。

NowdocはPHP5.3以降でのみ使える。

$greeting = "Hello";

// ヒアドキュメント
echo <<<EOS
$greeting, World!

EOS;
// => Hello, World!

// ヒアドキュメント
echo <<<"EOS"
$greeting, World!

EOS;
// => Hello, World!

// Nowdoc
echo <<<'EOS'
$greeting, World!

EOS;
// => $greeting, World!

ヒアドキュメント | PHP Manual
http://php.net/manual/ja/language.types.string.php#language.types.string.syntax.heredoc

Nowdoc | PHP Manual
http://php.net/manual/ja/language.types.string.php#language.types.string.syntax.nowdoc

Python

三重引用符(トリプルクオート) ''' または """ で囲むと複数行文字列を書くことができる。

"""\
foo
bar
"""

上記の例で1行目にバックスラッシュがあるのは最初の改行を文字列に含めないようにするため。

Ruby

str = <<EOS
foo
bar
EOS

クォーテーションで囲まないヒアドキュメントやダブルクオーテーションで囲んだヒアドキュメントは中の #{...} の部分がインライン展開される。シングルクオーテーションで囲んだヒアドキュメントはインライン展開されない。

greeting = "Hello"

p <<EOS
#{greeting}, World!
EOS
# => "Hello, World!\n"

p <<"EOS"
#{greeting}, World!
EOS
# => "Hello, World!\n"

p <<'EOS'
#{greeting}, World!
EOS
# => "\#{greeting}, World!\n"

バッククオート(```)で囲むと、コマンドとして実行され、その結果を文字列として取得できる。コマンド実行前に #{...} のインライン展開もされる。

command = 'date'
p <<`EOS`
#{command}
EOS
# => "Thu Mar 20 00:05:48 JST 2014\n"

複数のヒアドキュメントを1行で使うこともできる。

arr = [<<EOS, <<EOS]
aaa
EOS
bbb
EOS

p arr
# => ["aaa\n", "bbb\n"]

ヒアドキュメントは普通の文字列なので、その場でメソッドを呼び出すこともできる。

p <<EOS.length # => 8
foo
bar
EOS

<<のあとに-をつければ、終端の識別子の前にインデントを置くことができる。ただし、ヒアドキュメントの中身のインデントは文字列として含まれてしまう。

p <<-EOS
  foo
  bar
  EOS
# => "  foo\n  bar\n"

Ruby 1.9.3 リファレンスマニュアル > ヒアドキュメント
http://doc.ruby-lang.org/ja/1.9.3/doc/spec=2fliteral.html#here

Perl

変数展開されるヒアドキュメントの例

my $str = <<EOS;
aaa
bbb
EOS

my $str = <<"EOS";
aaa
bbb
EOS

変数展開されないヒアドキュメントの例

my $str = <<'EOS';
aaa
bbb
EOS

複数のヒアドキュメントを1行で使うこともできる。

my @arr = (<<EOS, <<EOS);
aaa
EOS
bbb
EOS

print @arr;
# =>
# aaa
# bbb

<<EOSEOSの部分を終端識別子と言い、裸のままにするかダブルクオートで囲むと、普通のダブルクオートで囲んだ文字列と同様に中の変数名が展開される。シングルクオートで囲めば、普通のシングルクオートで囲んだ文字列と同様に変数名は展開されない。

ヒアドキュメントがファイルの最後まで続くからといって終端の識別子を省略すると、エラーになってしまう。

ファイルの最後にテキストデータを置きたい場合は、ヒアドキュメントの代わりに __DATA__ を使うとよい。 __DATA__ とだけ書いた行があると、そこでperlのソースコードが終了しているものとみなし、かつその次の行からは main::DATA というファイルハンドルで読み出すことができる。

__DATA__ を使う例

print foreach (<main::DATA>);

__DATA__
Hello
World!

__DATA__ | perldoc.jp
http://perldoc.jp/docs/perl/5.18.1/perldata.pod#Special32Literals

sh (シェルスクリプト)

cat <<EOD
foo
bar
$HOME
`date`
EOD

ヒアドキュメントの中では `$ で始まる変数の展開が使える。それらを使いたくない場合は、以下のように最初の終端識別子の前にバックスラッシュ &#x5C; を付ける。

cat <<\EOD
MacBookPro 13-inch: $1499
MacBookPro 15-inch: $1999
EOD

ヒアドキュメントがファイルの最後までの場合は、最後の終端識別子を省略できる。

ヒアドキュメントの後にパイプで別のコマンドを繋ぎたい場合、ヒアドキュメントの後ろではなく前に書く。

cat <<EOD | sed s/o/0/g
foo
bar
EOD

出力は

f00
bar

となる。

複数のヒアドキュメントを1行で使うこともできる。

cat <<EOS; cat <<EOS
aaa
EOS
bbb
EOS

出力は

aaa
bbb

となる。

スクリプトの見やすさのためにヒアドキュメントの部分もインデントしたい場合、普通にインデントするとインデント自体もヒアドキュメントに含まれてしまうし、 EOD の終端子はインデントしたら終端子とみなしてくれないので、

if true; then
    cat << EOD
    Hello
EOD
fi

のよう残念な形になるし、以下のように出力自体にもインデントが含まれてしまう。

    Hello

この場合 << の代わりに <<- を使うとよい。ただしインデントはスペースではなくタブ限定である。

if true; then
    cat <<- EOD
    Hello
    EOD
fi

出力は

Hello

となる。

JavaScript

標準ではヒアドキュメントの仕組みはないが、似たようなことを実現する工夫はできるらしい。

Javascriptでヒアドキュメント | Miuran Business Systems
http://www.m-bsys.com/code/javascript-heredoc

このサイトは筆者(hydrocul)の個人メモの集合です。すべてのページは永遠に未完成です。