Ruby:連結なしで複数行の文字列を書くことはできますか?


397

これを少し見栄えよくする方法はありますか?

conn.exec 'select attr1, attr2, attr3, attr4, attr5, attr6, attr7 ' +
          'from table1, table2, table3, etc, etc, etc, etc, etc, ' +
          'where etc etc etc etc etc etc etc etc etc etc etc etc etc'

のように、連結を暗示する方法はありますか?


28
SQLインジェクション攻撃に注意してください。:)
ロイティンカー

回答:


595

この回答には必要なものを得るのに役立つ部分がありますが(余分な空白なしで簡単に複数行を連結できます)、実際の回答にはそれがなかったので、ここでコンパイルしています:

str = 'this is a multi-line string'\
  ' using implicit concatenation'\
  ' to prevent spare \n\'s'

=> "this is a multi-line string using implicit concatenation to eliminate spare
\\n's"

おまけとして、ここに面白いHEREDOC構文を使用したバージョンがあります(このリンク経由):

p <<END_SQL.gsub(/\s+/, " ").strip
SELECT * FROM     users
         ORDER BY users.id DESC
END_SQL
# >> "SELECT * FROM users ORDER BY users.id DESC"

後者は主に、処理に柔軟性を必要とする状況向けです。私は個人的には好きではありません。処理は文字列に対して奇妙な場所に置かれます(つまり、その前にありますが、通常は後に来るインスタンスメソッドを使用します)が、そこにあります。最後のEND_SQL識別子をインデントする場合(これは通常、関数またはモジュール内にあるため、一般的です)、ハイフン付きの構文を使用する必要があることに注意してください(つまり、のp <<-END_SQL代わりにp <<END_SQL)。それ以外の場合、インデントの空白により、識別子が文字列の続きとして解釈されます。

これはタイピングをそれほど節約しませんが、+記号を使用するよりも見栄えがよくなります。

また、(数年後の編集で言う)、Ruby 2.3+を使用している場合は、演算子<<〜も使用できます。これにより、最終的な文字列から余分なインデントが削除されます。.gsubその場合、呼び出しを削除できるはずです(ただし、開始インデントと最終的なニーズの両方に依存する場合があります)。

編集:もう1つ追加:

p %{
SELECT * FROM     users
         ORDER BY users.id DESC
}.gsub(/\s+/, " ").strip
# >> "SELECT * FROM users ORDER BY users.id DESC"

2
これは古い質問ですが、回答にエラーがあるか、それ以来構文が変更されています。p <<END_SQLでなければなりませんp <<-END_SQLそれ以外の場合はこれが答えです。オプションで、波状のHEREDOC演算子を使用して先頭の空白を取り除くことができます<<~END_SQL
jaydel

終了識別子がインデントされている場合のみエラーになります(ハイフンは、終了識別子を決定する前に空白を削除するようルビインタプリタに指示します)。ただし、そのことについて言及することはできます。また、〜は不要で、gsub \ s +とstripはすでに先頭の空白を削除しています。
A.ウィルソン

<<~答えに追加するのはいいでしょう、そこからそれを研究することになりました。個人的には<<~MSG.strip ... MSG、最後も削除する私が使用します\n
Qortex

1
私がこの回答を書いたとき(9年前、sheesh!)、Rubyは1.9であり、<<〜(明らかに)は2.3まで導入されませんでした。とにかく、古代の歴史はさておき、私はそれを取り上げます。
A.ウィルソン

余分な改行を追加しない数少ない回答の1つになっていただきありがとうございます。これは、この質問を見つけたときに回避しようとしていたことです。
Josh

174

Ruby 2.0では、次のように使用できます %

例えば:

SQL = %{
SELECT user, name
FROM users
WHERE users.id = #{var}
LIMIT #{var2}
}

14
Ruby 1.9.3でも動作します。
アンディスチュワート

26
この構文で作成された文字列には、改行と後続の行に追加されたインデントの両方が含まれます。
ジェームズ

これは<< EOT ...... EOT(ここのドキュメント)よりも優れています!必要に応じて補間も行います。
Nasser

1
@Nasserヒアドキュメントも補間を行います。
モニカの訴訟に資金を提供

3
Railsを使用する場合squishは、出力を呼び出すと便利です。
Jignesh Gohel 16

167

はい、挿入されている余分な改行を気にしない場合:

 conn.exec 'select attr1, attr2, attr3, attr4, attr5, attr6, attr7
            from table1, table2, table3, etc, etc, etc, etc, etc,
            where etc etc etc etc etc etc etc etc etc etc etc etc etc'

または、ヒアドキュメントを使用することもできます。

conn.exec <<-eos
   select attr1, attr2, attr3, attr4, attr5, attr6, attr7
   from table1, table2, table3, etc, etc, etc, etc, etc,
   where etc etc etc etc etc etc etc etc etc etc etc etc etc
eos

87
使用することもできます%Q(...)
BaroqueBobcat 2010

3
@ゾンビ:通常、SQLステートメントでは改行が許可され、通常の空白として扱われます。
Mark Byers、

2
例については、以下の私の回答を参照してください。今すぐ%を使用できます。
ロビーギルフォイル2013

4
次も使用できます%(...)
ゼロ除数

1
意図的に末尾の空白を追加してこれらの解決策の1つを使用する場合に留意すべき重要なことは、ファイルを保存するときにエディターが末尾のスペースを自動的に削除することです。私は通常、この動作を好みますが、予期しない問題を何度か引き起こしています。解決策は、OPが質問で行った方法のように複数行の文字列を記述することです。
Dennis

50

すでに読んだように、複数行の文字列には複数の構文があります。私のお気に入りはPerlスタイルです。

conn.exec %q{select attr1, attr2, attr3, attr4, attr5, attr6, attr7
      from table1, table2, table3, etc, etc, etc, etc, etc,
      where etc etc etc etc etc etc etc etc etc etc etc etc etc}

複数行の文字列は%qで始まり、その後に{、[または(が続き、対応する反転文字で終わります。%qでは補間が許可されません。%Qでは、次のように記述できます。

conn.exec %Q{select attr1, attr2, attr3, attr4, attr5, attr6, attr7
      from #{table_names},
      where etc etc etc etc etc etc etc etc etc etc etc etc etc}

実際には、このような複数行の文字列がどのように呼び出されるかはわかりません。Perlの複数行と呼ぶことにしましょう。

ただし、マークとピーターが示唆したように、Perlの複数行を使用するか、ヒアドキュメントを使用するかにかかわらず、潜在的に不要な空白が生じることに注意してください。私の例とその例の両方で、「from」行と「where」行には、コード内のインデントのために先頭の空白が含まれています。この空白文字が望ましくない場合は、現在行っているように連結文字列を使用する必要があります。


4
この例では#{table_names}は機能しません。%q {}を使用したため、%q []または()を使用した場合は機能します
MatthewFord

2
この点で私のお気に入りは、単に%{補間サポート付きのスーパーマルチライン文字列}
Duke

%qファミリから生成された文字列には、元のコードと同等ではない改行が含まれます。
Josh

29

次の\nような改行文字を削除する価値がある場合があります。

conn.exec <<-eos.squish
 select attr1, attr2, attr3, attr4, attr5, attr6, attr7
 from table1, table2, table3, etc, etc, etc, etc, etc,
 where etc etc etc etc etc etc etc etc etc etc etc etc etc
eos

5
これはルビーではなくレールベースです
a14m

23

二重引用符も使用できます

x = """
this is 
a multiline
string
"""

2.3.3 :012 > x
 => "\nthis is\na multiline\nstring\n"

改行「\ n」を削除する必要がある場合は、各行の終わりにバックスラッシュ「\」を使用します


5
単一の二重引用符で同じ結果を得ることができます。Rubyには三重二重引用符のようなものはありません。単にと解釈します"" + "double quotes with some content" + ""
rakvium、2018年

ええ、でも `" "+" \ nこんにちは\ n "+" "奇妙に見えます
juliangonzalez

1
はい、奇妙に見えます。同じ結果で単数の二重引用符を使用できる場合に、余分な二重引用符を追加する理由がないのはこのためです。
rakvium

はい、私はプラス記号を意味しました。それなしの二重引用符は見栄えがよく、読みやすく、一重引用符の代わりに見つけやすくなります。これは、単一行の文字列で使用する必要があります。
juliangonzalez

1
つまり、"x"見た目が良く、"""x"""(基本的にはと同じ""+"x"+"")または"""""x"""""(と同じ)より速く動作します"" + "" + "x" + "" + ""。これはPythonではなくRubyであり、複数行の文字列が必要な場合の"""代わりに使用し"ます。
rakvium

15
conn.exec = <<eos
  select attr1, attr2, attr3, attr4, attr5, attr6, attr7
  from table1, table2, table3, etc, etc, etc, etc, etc,
  where etc etc etc etc etc etc etc etc etc etc etc etc etc
eos

1
「<<-eos」のように「-」なしでヒアドキュメントを使用すると、追加のリーダースペースが含まれます。Mark Byersの応答を参照してください。
2016

ヒアドキュメントには、元のコードと同等ではない改行が含まれます。
Josh

15

その他のオプション:

#multi line string
multiline_string = <<EOM
This is a very long string
that contains interpolation
like #{4 + 5} \n\n
EOM

puts multiline_string

#another option for multiline string
message = <<-EOF
asdfasdfsador #{2+2} this month.
asdfadsfasdfadsfad.
EOF

puts message

1
に変更<<EOMする必要が<<-EOMありますか?
kingPuppy

たぶん、それは私の<<-EOF例ではうまくいったようです。私の推測では、どちらの方法でも機能します。
Alex Cohen

ヒアドキュメントには、元のコードと同等ではない改行が含まれます。
Josh

11

最近、Ruby 2.3の新機能をsquiggly HEREDOC使用すると、変更によって最小限の変更で複数行の文字列を適切に記述できるため、これを.squish(レールを使用している場合)と組み合わせて使用​​すると、複数行を適切に記述できます。ただルビーを使用した場合には、あなたが行うことができます<<~SQL.split.join(" ")している、ほぼ同じ

[1] pry(main)> <<~SQL.squish
[1] pry(main)*   select attr1, attr2, attr3, attr4, attr5, attr6, attr7
[1] pry(main)*   from table1, table2, table3, etc, etc, etc, etc, etc,
[1] pry(main)*   where etc etc etc etc etc etc etc etc etc etc etc etc etc
[1] pry(main)* SQL
=> "select attr1, attr2, attr3, attr4, attr5, attr6, attr7 from table1, table2, table3, etc, etc, etc, etc, etc, where etc etc etc etc etc etc etc etc etc etc etc etc etc"

ref:https : //infinum.co/the-capsized-eight/multiline-strings-ruby-2-3-0-the-squiggly-heredoc


スキッシュはルビーではなくレール
Josh

1
@ジョシュ、そうそうそう、答えを更新して、乾杯。
Mark Jad

6
conn.exec 'select attr1, attr2, attr3, attr4, attr5, attr6, attr7 ' <<
        'from table1, table2, table3, etc, etc, etc, etc, etc, ' <<
        'where etc etc etc etc etc etc etc etc etc etc etc etc etc'

<<は文字列の連結演算子です


2
+通常の連結演算子で、<<あるインプレース追記演算子。リテラルに副作用を使用すると、ここで機能します(最初の文字列が2回変更されて返されます)が、奇妙であり、+完全に明確であるダブルテイクを実行させます。しかし、多分私はRubyが初めての人かもしれません...
Beni Cherniavsky-Paskin

frozen_string_literal有効になっている場合、これは機能しません
Raido

6

余分なスペースと改行を気にしない場合は、

conn.exec %w{select attr1, attr2, attr3, attr4, attr5, attr6, attr7
  from table1, table2, table3, etc, etc, etc, etc, etc,
  where etc etc etc etc etc etc etc etc etc etc etc etc etc} * ' '

(補間された文字列には%Wを使用)


これは、使用の組み合わせがはるかに多くなるため、非常に気に入っています。
schmijos 2015年

1
これにより、隣接する複数のスペースが1つに圧縮されます。(改行+次のインデントのつぶしはここでの勝利ですが、行の途中でそれは驚くかもしれません。)
Beni Cherniavsky-Paskin

5

各行の括弧を閉じないようにするには、バックスラッシュを付けた二重引用符を使用して改行をエスケープします。

"select attr1, attr2, attr3, attr4, attr5, attr6, attr7 \
from table1, table2, table3, etc, etc, etc, etc, etc, \
where etc etc etc etc etc etc etc etc etc etc etc etc etc"

これは実際に質問に答えるこのページの数少ない回答の1つです!
Josh

4
conn.exec [
  "select attr1, attr2, attr3, ...",
  "from table1, table2, table3, ...",
  "where ..."
].join(' ')

この提案には、ヒアドキュメントや自動インデンターが文字列の各部分を適切にインデントできる長い文字列よりも優れています。しかし、これには効率コストが伴います。


@Aidan、コンマをバックスラッシュ(la C)で置き換えることができ、結合(または配列)は必要ありません。インタプリタは(私が思う)解析時に文字列を連結し、他のほとんどの方法と比べてかなり高速になります。 。ただし、文字列の配列を結合することの1つの利点は、一部の自動インデンターが、たとえばhere-doc文字列や\を使用する場合よりも優れた機能を果たすことです。
ウェインコンラッド

1
ヒアドキュメントの構文<<-では、適切なインデントが可能です。
A.ウィルソン、

3

Ruby 2.3以降のRuby-way(TM):波線のHEREDOC <<~ を使用して、改行と適切なインデントで複数行の文字列を定義します。

conn.exec <<~EOS
            select attr1, attr2, attr3, attr4, attr5, attr6, attr7
            from table1, table2, table3, etc, etc, etc, etc, etc
            where etc etc etc etc etc etc etc etc etc etc etc etc etc
          EOS

# -> "select...\nfrom...\nwhere..."

適切なインデントが問題にならない場合は、一重引用符と二重引用符がRubyの複数行にまたがることがあります。

conn.exec "select attr1, attr2, attr3, attr4, attr5, attr6, attr7 
           from table1, table2, table3, etc, etc, etc, etc, etc, 
           where etc etc etc etc etc etc etc etc etc etc etc etc etc"    

# -> "select...\n           from...\n           where..."

大量のエスケープが必要になるため、一重引用符または二重引用符が扱いにくい場合は、パーセント文字列リテラル表記 %が最も柔軟なソリューションです。

conn.exec %(select attr1, attr2, attr3, attr4, attr5, attr6, attr7
            from table1, table2, table3, etc, etc, etc, etc, etc
            where (ProductLine = 'R' OR ProductLine = "S") AND Country = "...")
# -> "select...\n            from...\n            where..."

改行(波線HEREDOC、引用符、パーセント文字列リテラルの両方が原因)を回避することが目的である場合は、バックスラッシュを行の最後の非空白文字として置くことにより、行の継続を使用できます\。これにより、行が継続され、Rubyは文字列を連続して連結します(引用符で囲まれた文字列内のスペースに注意してください)。

conn.exec 'select attr1, attr2, attr3, attr4, attr5, attr6, attr7 ' \
          'from table1, table2, table3, etc, etc, etc, etc, etc, ' \
          'where etc etc etc etc etc etc etc etc etc etc etc etc etc'

# -> "select...from...where..."

Railsを使用String.squishすると、先頭と末尾のスペースの文字列が削除され、連続するすべての空白(改行、タブなど)が1つのスペースに折りたたまれます。

conn.exec "select attr1, attr2, attr3, attr4, attr5, attr6, attr7 
           from table1, table2, table3, etc, etc, etc, etc, etc, 
           where etc etc etc etc etc etc etc etc etc etc etc etc etc".squish

# -> "select...attr7 from...etc, where..."

詳細:

Ruby HEREDOC構文

文字列のヒアドキュメント表記は、コード内の長いテキストブロックをインラインで指定する方法です。最初に<<ユーザー定義の文字列(文字列の終了記号)が続きます。次のすべての行は、文字列の終わりのターミネータが行の先頭で見つかるまで連結されます。

puts <<HEREDOC 
Text Text Text Text
Bla Bla
HEREDOC
# -> "Text Text Text Text\nBlaBla"

End of Stringターミネータは自由に選択できますが、 "EOS"(End of String)などの文字列、または "SQL"などの文字列のドメインに一致する文字列を使用するのが一般的です。

HEREDOCは、デフォルトで、またはEOSターミネーターが二重引用符で囲まれている場合に補間をサポートします。

price = 10
print <<"EOS"  # comments can be put here
1.) The price is #{price}.
EOS
# -> "1.) The price is 10."

EOSターミネータが一重引用符で囲まれている場合、補間を無効にできます。

print <<'EOS' # Disabled interpolation
3.) The price is #{price}.
EOS
# -> "3.) The price is #{price}."

の1つの重要な制限は、<<HEREDOCEnd of Stringターミネーターが行の先頭にある必要があることです。

  puts <<EOS 
    def foo
      print "foo"
    end
  EOS
EOS
#-> "....def foo\n......print "foo"\n....end\n..EOS

これを回避するために、<<-構文が作成されました。EOSターミネータをインデントして、コードの見栄えを良くすることができます。<<-EOSターミネーターとEOSターミネーターの間の行は、すべてのインデントを含む完全な範囲で使用されています。

puts <<-EOS # Use <<- to indent End of String terminator
  def foo
    print "foo"
  end
EOS
# -> "..def foo\n....print "foo"\n..end"

Ruby 2.3以降、<<~先頭の空白を削除する波状のHEREDOCがあります。

puts <<~EOS # Use the squiggly HEREDOC <<~ to remove leading whitespace (since Ruby 2.3!)
  def foo
    print "foo"
  end
EOS
# -> "def foo\n..print "foo"\nend"

空行およびタブとスペースのみを含む行は<<〜によって無視されます

puts <<~EOS.inspect 
  Hello

    World!
EOS
#-> "Hello\n..World!"

タブとスペースの両方が使用されている場合、タブは8つのスペースと見なされます。最もインデントされていない行がタブの中央にある場合、このタブは削除されません。

puts <<~EOS.inspect
<tab>One Tab
<space><space>Two Spaces
EOS
# -> "\tOne Tab\nTwoSpaces"

HEREDOCは、バックティックを使用してコマンドを実行するなど、いくつかのクレイジーなことを実行できます。

puts <<`EOC`            
echo #{price}
echo #{price * 2}
EOC

HEREDOC文字列定義は「スタック」することができます。つまり、最初のEOSターミネーター(下のEOSFOO)は最初の文字列を終了し、2番目の文字列(下のEOSBAR)を開始します。

print <<EOSFOO, <<EOSBAR    # you can stack them
I said foo.
EOSFOO
I said bar.
EOSBAR

だれもそれをそのように使用することはないと思いますが、これ<<EOSは実際には単なる文字列リテラルであり、文字列を通常配置できる場所ならどこにでも配置できます。

def func(a,b,c)
  puts a
  puts b
  puts c
end

func(<<THIS, 23, <<THAT) 
Here's a line
or two.
THIS
and here's another.
THAT

Ruby 2.3がなく、Rails >=3.0 がない場合は、次のように使用できますString.strip_heredoc<<~

# File activesupport/lib/active_support/core_ext/string/strip.rb, line 22
class String
  def strip_heredoc
    gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, "".freeze)
  end
end

puts <<-USAGE.strip_heredoc # If no Ruby 2.3, but Rails >= 3.0
  This command does such and such.

  Supported options are:
    -h         This message
    ...
USAGE

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

参照してくださいRubyDocようなペア括弧内の文字列が続くパーセント記号を使用する方法については%(...)%[...]%{...}など、または任意の英数字以外の文字のペアなどを%+...+

最後の言葉

最後に、元の質問「連結を暗示する方法はありますか?」回答:2つの文字列(一重引用符と二重引用符)が連続して見つかった場合、Rubyは常に連結を意味します。

puts "select..." 'from table...' "where..."
# -> "select...from table...where..."

Rubyがステートメントの終わりを解釈しているため、これは改行を超えて機能しないこと、および結果として行にある文字列だけの結果としての行は何もしないことに注意してください。


1

今日のエレガントな答え:

<<~TEXT
Hi #{user.name}, 

Thanks for raising the flag, we're always happy to help you.
Your issue will be resolved within 2 hours.
Please be patient!

Thanks again,
Team #{user.organization.name}
TEXT

との違いが<<-TEXTあります<<~TEXT、前者はブロック内の間隔を保持し、後者は保持しません。

他のオプションもあります。連結などのようですが、これは一般的にもっと意味があります。

ここで私が間違っている場合は、方法を教えてください...


ヒアドキュメントには、元のコードと同等ではない改行が含まれます。
Josh

1

あなたのように、改行含まない解決策も探していました。(SQLでは安全かもしれませんが、私の場合は安全ではなく、処理するテキストの大きなブロックがあります)

これは間違いなく醜いですが、ヒアドキュメントの改行をバックスラッシュでエスケープして、結果の文字列からそれらを省略することができます。

conn.exec <<~END_OF_INPUT
    select attr1, attr2, attr3, attr4, attr5, attr6, attr7 \
    from table1, table2, table3, etc, etc, etc, etc, etc, \
    where etc etc etc etc etc etc etc etc etc etc etc etc etc
  END_OF_INPUT

補間せずにこれを実行することはできないことに注意してください(IE <<~'END_OF_INPUT')。注意してください。#{expressions}ここでは評価されますが、元のコードでは評価されません。A.そのため、ウィルソンの答えの方が良いかもしれません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.