如何从Ruby HEREDOC中删除前导空格字符?

Chr*_*ier 83 ruby whitespace heredoc

我正在尝试制作一个Ruby heredoc的问题.它正在返回每行的前导空格,即使我包含 - 运算符,它应该抑制所有前导空白字符.我的方法看起来像这样:

    def distinct_count
    <<-EOF
        \tSELECT
        \t CAST('#{name}' AS VARCHAR(30)) as COLUMN_NAME
        \t,COUNT(DISTINCT #{name}) AS DISTINCT_COUNT
        \tFROM #{table.call}
    EOF
end
Run Code Online (Sandbox Code Playgroud)

我的输出如下:

    => "            \tSELECT\n            \t CAST('SRC_ACCT_NUM' AS VARCHAR(30)) as
COLUMN_NAME\n            \t,COUNT(DISTINCT SRC_ACCT_NUM) AS DISTINCT_COUNT\n
        \tFROM UD461.MGMT_REPORT_HNB\n"
Run Code Online (Sandbox Code Playgroud)

当然,这在这个特定的例子中是正确的,除了第一个"和\ t之间的所有空格.有没有人知道我在这里做错了什么?

Phi*_*oss 131

<<-heredoc 的形式只忽略末尾分隔符的前导空格.

使用Ruby 2.3及更高版本,您可以使用波浪形的heredoc(<<~)来抑制内容行的前导空格:

def test
  <<~END
    First content line.
      Two spaces here.
    No space here.
  END
end

test
# => "First content line.\n  Two spaces here.\nNo space here.\n"
Run Code Online (Sandbox Code Playgroud)

从Ruby 文字文档:

最小缩进行的缩进将从内容的每一行中删除.请注意,为了确定缩进,将忽略仅由文字制表符和空格组成的空行和行,但转义制表符和空格被视为非缩进字符.

  • 我喜欢在提出这个问题5年后,这仍然是一个相关主题.感谢更新的回复! (8认同)
  • @ChrisDrappier 不确定这是否可行,但我建议将这个问题的公认答案更改为这个问题,因为现在这显然是解决方案。 (2认同)

chr*_*isk 122

如果您使用的是Rails 3.0或更高版本,请尝试#strip_heredoc.文档中的这个示例打印前三行没有缩进,同时保留最后两行的两个空格缩进:

if options[:usage]
  puts <<-USAGE.strip_heredoc
    This command does such and such.
 
    Supported options are:
      -h         This message
      ...
  USAGE
end
Run Code Online (Sandbox Code Playgroud)

该文件还指出:"从技术上讲,它看起来整个字符串中的至少缩进线,并删除前导空格的量."

这是active_support/core_ext/string/strip.rb的实现:

class String
  def strip_heredoc
    indent = scan(/^[ \t]*(?=\S)/).min.try(:size) || 0
    gsub(/^[ \t]{#{indent}}/, '')
  end
end
Run Code Online (Sandbox Code Playgroud)

您可以在test/core_ext/string_ext_test.rb中找到测试.

  • iconoclast是正确的; 只需`require"active_support/core_ext/string"`首先 (3认同)
  • 您仍然可以在Rails 3之外使用它! (2认同)
  • 在ruby 1.8.7中似乎不起作用:`try`没有为String定义.事实上,它似乎是一个特定于轨道的构造 (2认同)

ein*_*nus 44

没什么可做的,我知道我害怕.我经常这样做:

def distinct_count
    <<-EOF.gsub /^\s+/, ""
        \tSELECT
        \t CAST('#{name}' AS VARCHAR(30)) as COLUMN_NAME
        \t,COUNT(DISTINCT #{name}) AS DISTINCT_COUNT
        \tFROM #{table.call}
    EOF
end
Run Code Online (Sandbox Code Playgroud)

这有效,但有点黑客.

编辑:从下面的Rene Saarsoo获取灵感,我建议这样的事情:

class String
  def unindent 
    gsub(/^#{scan(/^\s*/).min_by{|l|l.length}}/, "")
  end
end

def distinct_count
    <<-EOF.unindent
        \tSELECT
        \t CAST('#{name}' AS VARCHAR(30)) as COLUMN_NAME
        \t,COUNT(DISTINCT #{name}) AS DISTINCT_COUNT
        \tFROM #{table.call}
    EOF
end
Run Code Online (Sandbox Code Playgroud)

这个版本应该处理第一行不是最左边的那一行.

  • 我有点希望Ruby的破折号HEREDOC语法在bash中更像是那样,那么我们就不会有这个问题了!(参见[此bash示例](http://tldp.org/LDP/abs/html/here-docs.html#EX71A)) (2认同)

Phr*_*ogz 22

这是我使用的一个更简单的unindent脚本版本:

class String
  # Strip leading whitespace from each line that is the same as the 
  # amount of whitespace on the first line of the string.
  # Leaves _additional_ indentation on later lines intact.
  def unindent
    gsub /^#{self[/\A[ \t]*/]}/, ''
  end
end
Run Code Online (Sandbox Code Playgroud)

像这样使用它:

foo = {
  bar: <<-ENDBAR.unindent
    My multiline
      and indented
        content here
    Yay!
  ENDBAR
}
#=> {:bar=>"My multiline\n  and indented\n    content here\nYay!"}
Run Code Online (Sandbox Code Playgroud)

如果第一行可能比其他行缩进更多,并希望(如Rails)基于最小缩进行而取消,您可能希望使用:

class String
  # Strip leading whitespace from each line that is the same as the 
  # amount of whitespace on the least-indented line of the string.
  def strip_indent
    if mindent=scan(/^[ \t]+/).min_by(&:length)
      gsub /^#{mindent}/, ''
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

请注意,如果您扫描\s+而不是[ \t]+您,最终可能会从您的heredoc中删除换行符而不是前导空格.不可取!


Bri*_*ell 7

<<-在Ruby中只会忽略结束分隔符的前导空格,允许它正确缩进.尽管网上有些文档可能会说,但它并没有删除字符串内部行的前导空格.

您可以使用gsub以下方法自行删除前导空格:

<<-EOF.gsub /^\s*/, ''
    \tSELECT
    \t CAST('#{name}' AS VARCHAR(30)) as COLUMN_NAME
    \t,COUNT(DISTINCT #{name}) AS DISTINCT_COUNT
    \tFROM #{table.call}
EOF
Run Code Online (Sandbox Code Playgroud)

或者,如果您只想删除空格,请留下标签:

<<-EOF.gsub /^ */, ''
    \tSELECT
    \t CAST('#{name}' AS VARCHAR(30)) as COLUMN_NAME
    \t,COUNT(DISTINCT #{name}) AS DISTINCT_COUNT
    \tFROM #{table.call}
EOF
Run Code Online (Sandbox Code Playgroud)

  • @Phrogz OP提到他希望它"压制所有领先的空白字符",所以我给出了一个答案就是这样做,以及一个只剥离空格而不是标签的答案,以防他正在寻找的东西.几个月之后,为OP提供了有效的答案,发布你自己的竞争答案有点蹩脚. (7认同)
  • 最后,我想谈谈"竞争回答"这个短语.你和我都不应该竞争,也不相信我们._(虽然如果我们这样,你现在就赢得了27.4k的代表.)_我们帮助有个人(OP)和匿名(通过谷歌到达的人)遇到问题的人.更多(有效)答案有帮助.在那种情况下,我重新考虑我的downvote.你是对的,你的答案没有害处,误导或被高估.我现在已经编辑了你的问题,这样我就可以给你带走的2点代表. (4认同)

saw*_*awa 6

一些其他答案找到最小缩进行的缩进级别,并从所​​有行中删除它,但考虑到编程中缩进的性质(第一行是最少缩进的),我认为你应该寻找缩进级别的第一行.

class String
  def unindent; gsub(/^#{match(/^\s+/)}/, "") end
end
Run Code Online (Sandbox Code Playgroud)