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'

比如,有没有办法暗示串联?

450127 次浏览

是的,如果你不介意额外的换行被插入:

 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'

或者你也可以使用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
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
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'

& lt; & lt;串接操作符是字符串吗

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

这个建议的优点在于,自动缩进器可以适当地缩进文档和长字符串的每个部分。但这是以效率为代价的。

多行字符串有多种语法,你已经读过了。我最喜欢的是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 multilines吧。

但是请注意,无论您使用的是Perl多行还是像Mark和Peter建议的那样使用heredocs,最终都会出现潜在的不必要的空格。在我的例子和他们的例子中,“from”和“where”行都包含前导空白,因为它们在代码中的缩进。如果不需要这个空格,那么您必须像现在这样使用连接的字符串。

这个答案中有一些部分帮助我得到了我需要的东西(简单的多行连接,没有额外的空格),但由于没有实际的答案,我在这里编译它们:

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"

后者主要用于在处理过程中需要更大灵活性的情况。我个人不喜欢它,它把处理放在一个奇怪的地方w.r.t.字符串(即,在它前面,但使用实例方法通常在后面),但它在那里。注意,如果要缩进最后一个END_SQL标识符(这很常见,因为它可能在函数或模块中),则需要使用连字符语法(即p <<-END_SQL而不是p <<END_SQL)。否则,缩进空格会导致标识符被解释为字符串的延续。

这并没有节省太多的输入,但对我来说,它看起来比使用+号更好。

此外(我在几年后的编辑中说),如果你使用Ruby 2.3+,操作符<<~ 也是可用的,它会从最终的字符串中删除额外的缩进。在这种情况下,您应该能够删除.gsub调用(尽管这可能取决于开始缩进和最终需求)。

编辑:再加一个:

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

如果你介意额外的空格和换行,你可以使用

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表示插值字符串)

在ruby 2.0中,你现在可以只使用%

例如:

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

有时值得删除新的行字符\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

为了避免每一行的圆括号关闭,你可以简单地使用双引号和反斜杠来转义换行:

"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"

其他选项:

#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

你也可以使用双引号

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


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

如果需要删除换行符“\n”,请在每行末尾使用反斜杠“\”

最近,随着Ruby 2.3的新特性,新的squiggly HEREDOC将允许你以一种很好的方式编写多行字符串,并且只做了最小的更改,所以将它与.squish(如果你使用的是rails)结合使用,将让你以一种很好的方式编写多行字符串! 在只使用ruby的情况下,你可以做一个<<~SQL.split.join(" "),它是几乎< em > < / em >,相同的

[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"

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

今天的优雅回答:

<<~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有区别,前者保留块内的间距,而后者则没有。

还有其他的选择。 就像串联等,但这个在一般情况下更有意义

如果我错了,请告诉我…

这个问题让我开始理解HEREDOC是如何工作的。如果答案太长,请原谅。

当你想要定义一个带有换行符和适当缩进的多行字符串(自Ruby 2.3起可用)时, 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将剥离字符串的前导和尾随空格,并将所有连续的空格(换行符、制表符和所有空格)折叠成一个空格:

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"

字符串结束结束符可以自由选择,但通常使用"EOS"(字符串的结尾)或者匹配字符串域的东西,比如"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}."

<<HEREDOC的一个重要限制是字符串结束符必须在行首:

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

为了解决这个问题,创建了<<-语法。它允许EOS终止符缩进以使代码看起来更好。<<-和EOS结束符之间的行仍然完整地使用,包括所有缩进:

def printExample
puts <<-EOS # Use <<- to indent End of String terminator
def foo
print "foo"
end
EOS
end
# -> "....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)将结束第一个字符串,并开始第二个字符串(下面的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

故障排除

如果在Ruby解析文件时看到错误,那么很有可能是使用了herdoc的额外前导或尾随空格,或者使用了弯弯曲曲的HEREDOC的额外尾随空格。例如:

你看到了什么:

    database_yml = <<~EOS
production:
database: #{fetch(:user)}
adapter: postgresql
pool: 5
timeout: 5000
EOS

Ruby告诉你:

SyntaxError: .../sample.rb:xx: can't find string "EOS" anywhere before EOF
...sample.rb:xx: syntax error, unexpected end-of-input, expecting `end'

错在哪里:

在终止EOS后标记额外的空格

找出终止EOS后的额外空格。

百分比字符串字面量

参见RubyDoc了解如何使用百分比符号后跟括号中的字符串,如%(...)%[...]%{...}等,或任何非字母数字字符的一对,如%+...+

最后一句话

最后,要得到原始问题“是否有一种方法来暗示串联?”的答案; Ruby总是暗示如果两个字符串(单引号和双引号)背对背地找到:

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

需要注意的是,这不能跨换行,因为Ruby正在解释语句的结束,而一行中仅包含字符串的后续行不会执行任何操作。

像你一样,我也在寻找一个解决方案不包括换行符。(虽然它们在SQL中可能是安全的,但在我的情况下不安全,我有一个大的文本块要处理)

这可以说是同样丑陋,但你可以在heredoc中反斜杠转义换行符,以从结果字符串中省略它们:

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

注意,你不能在没有插值(即<<~'END_OF_INPUT')的情况下due this,所以要小心。#{expressions}将在这里求值,而在您的原始代码中不会求值。因此,威尔逊的回答可能更好。