Ruby:我可以编写没有连接的多行字符串吗?


396

有没有办法使它看起来更好一点?

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注入攻击。:)
罗伊·廷克

Answers:


594

这个答案有很多片段可以帮助我获得所需的信息(轻松的多行连接,而无需多余的空格),但是由于没有实际的答案,因此我在这里进行了编译:

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在这种情况下,您应该能够删除该调用(尽管它可能取决于起始缩进和最终需求)。

编辑:再添加一个:

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

如果缩进了结尾标识符,这只是一个错误(连字符告诉ruby解释器在确定结尾标识符之前先修剪空格)。不过,我可以提个便笺提及。另外,〜是不必要的,gsub \ s +和strip已经删除了前导空格。
威尔逊

添加<<~到答案将是很好,最终从那里进行了研究。就个人而言,我使用<<~MSG.strip ... MSG它也剥离了最后一个\n
Qortex

1
当我写这个答案时(九年前,嘘!),Ruby是1.9,而<<〜(显然)直到2.3才被引入。无论如何,除了古老的历史,我将其放入其中,感谢您提出来。
A.威尔逊

感谢您成为不添加额外的换行符的少数答案之一,这是我在发现此问题时要避免的方法。
乔什

174

在ruby 2.0中,您现在可以使用 %

例如:

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

14
也可以在Ruby 1.9.3中使用。
安迪·斯图尔特

26
使用此语法创建的字符串将包括换行符和添加到后续行的任何缩进。
詹姆斯

这甚至比<< EOT ...... EOT(此处文档)还要好!如果需要,它也会进行插值。
纳赛尔2015年

1
@Nasser Heredoc也可以进行插值。
基金莫妮卡的诉讼

3
如果使用Rails squish,则在输出上调用会有所帮助。
Jignesh Gohel 2016年

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'

另外,您可以使用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

87
您也可以使用%Q(...)
BaroqueBobcat 2010年

3
@Zombies:SQL语句中通常允许使用换行符,并且仅将它们视为普通的空格。
Mark Byers 2010年

2
请参阅以下我的答案作为示例,您可以立即使用%。
罗比·吉尔福伊

4
您还可以使用%(...)
零除法

1
如果有意添加尾随空格并使用以下解决方案之一,则要记住的重要一点是,编辑器在保存文件时可能会自动删除尾随空格。尽管我通常更喜欢这种行为,但它却多次给我造成了意想不到的问题。一种解决方案是像OP在问题中那样编写多行字符串。
丹尼斯

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开头,后跟{,[或(,然后以相应的反向字符结束。

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多行还是Mark和Peter所建议的heredocs,最终都可能会出现不必要的空格。在我的示例及其示例中,“ from”和“ where”行均因其在代码中的缩进而包含前导空格。如果不需要此空格,则必须像现在这样使用串联字符串。


4
#{table_names}中的from在本示例中不起作用,因为您使用了%q {},如果您使用%q []或(),它就可以工作
MatthewFord 2011年

2
我最喜欢的是%{具有插值支持的超级多行字符串}
Duke

%q系列产生的字符串将包含换行符,这与原始代码不相等。
乔什

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 '16

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

是的,但是`“” +“ \ n你好\ n” +“”看起来很奇怪
juliangonzalez

1
是的,这看起来很奇怪,这就是为什么当您可以使用具有相同结果的单数双引号时,没有理由添加额外的双引号的原因。
rakvium

是的,我的意思是加号。不用单引号的双引号看起来不错,可读性强,更容易发现,而不是单引号,应该在单行字符串上使用。
juliangonzalez

1
我的意思是,它"x"看上去比"""x"""(基本上相同""+"x"+"")或"""""x"""""(与相同)更好并且工作更快"" + "" + "x" + "" + ""。使用Ruby,而不是Python,"""而不是"在需要多行字符串时使用。
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'中一样,在不使用'-'的情况下使用heredoc,将包含其他前导空格。请参阅Mark Byers的回应。
2016年

Heredoc将包含与原始代码不等效的换行符。
乔什

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例子有用。我的猜测是任何一种方法都可以。
亚历克斯·科恩

Heredoc将包含与原始代码不等效的换行符。
乔什

11

最近,有了Ruby 2.3的新功能,新功能squiggly HEREDOC将使您以最少的变化就能以一种不错的方式编写多行字符串,因此结合使用.squish(如果您使用的是rails)将使您以一种不错的方式编写多行!在仅仅使用红宝石的情况下,你可以做一个<<~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"

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


挤压是铁轨,而不是红宝石
乔什

1
@Josh,是的,您是对的,更新了答案,欢呼。
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
+是常规串联运算符,<<就地附加运算符。在文字上使用副作用碰巧在这里起作用(第一个字符串被修改了两次并返回),但是恕我直言,这很奇怪,让我做了两次尝试,+这很清楚。但也许我只是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
这会将多个相邻的空间压缩为一个。(压缩换行符+紧缩在这里是一个胜利,但在中间可能会令人惊讶。)
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"

这是此页面上实际上可以回答问题的少数答案之一!
乔什

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

此建议相对于此处文档和长字符串具有优势,即自动缩进可以适当缩进字符串的每个部分。但这是以效率为代价的。


@Aidan,您可以使用反斜杠(a la C)替换逗号,而无需连接(或数组):解释器将在(我认为)解析时将字符串连接起来,与大多数替代方法相比,它很快。但是,连接字符串数组的一个优点是,某些自动缩进的功能比使用诸如this-doc字符串或\更好。
韦恩·康拉德

1
请注意,heredoc语法<<-将允许适当的缩进。
A.威尔逊

2

从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则会删除前导和尾随字符串,并将所有连续的空格(换行符,制表符和所有空格)折叠为一个空格:

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...from...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终止符之间的行仍然完整使用,包括所有缩进:

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)将结束第一个字符串并开始第二个字符串(下面的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如何使用百分号然后在括号中的字符串进行配对,诸如%(...)%[...]%{...}等,或一对任何非字母数字字符的诸如%+...+

最后的话

最后,要获得对原始问题“是否有隐含串联的方法?”的答案。回答:如果找到两个背对背的字符串(单引号和双引号),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,前者保留了块内的间距,而后者则没有。

还有其他选择。像串联等,但是从总体上讲,这更有意义。

如果我错了,请告诉我如何...


Heredoc将包含与原始代码不等效的换行符。
乔什

1

和您一样,我也在寻找不包含换行符的解决方案。(尽管它们在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

请注意,如果没有插值(IE <<~'END_OF_INPUT'),您将无法做到这一点,因此请小心。#{expressions}将在此处进行评估,而不会在您的原始代码中进行评估。因此,威尔逊的答案可能会更好。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.