【问题标题】:Where is this newline coming from?这个换行符是从哪里来的?
【发布时间】:2010-07-02 17:36:13
【问题描述】:

我正在使用 rake 脚本来标记我的 .NET 项目中的 AssemblyInfo.cs 文件,但是引入的幻像回车(或换行符等)会破坏编译。获取版本号的方法是:

def get_version()
  version = ''
  IO.popen("#{SVNVERSION_APPLICATION} #{build_info.root_dir}") do |output|
    output.readlines.each do |line|
      version << line.gsub(/\:.*/, '')
    end
  end
  result = version
end

如果有更好的方法,请告诉我。我主要在这里修修补补(这实际上是我曾经研究过的第一个 Ruby,所以请耐心等待)。如您所见(而且我的正则表达式技能从未真正达到忍者水平)我只是想摆脱第一个冒号及其之后的所有内容。 Svnversion 返回诸如“64:67M”之类的东西,我只对第一个数字感兴趣。

然后我这样标记文件:

contents = contents.gsub(/AssemblyVersion\(\"([\d.*]*)\"\)/, "AssemblyVersion(\"#{helper.build_info.build_number_template}\")")

当然,围绕这些位还有更多代码。这只是正在发生的事情的实质。基本上,在任务中,我调用 get_version 将版本号存储在辅助对象上,该对象稍后用于将 AssemblyInfo.cs 文件读入“内容”并进行替换并将其写回的方法中。

除了输出中的幻象换行符外,一切正常:

[assembly: AssemblyVersion("1.1.0.62
")]
[assembly: AssemblyFileVersion("1.1.0.62
")]

我尝试添加另一个 .gsub 以尝试过滤掉 \n 和 \r,但没有成功,我尝试过 .chomp 等。它似乎总是将换行符放在结果文件中。

我是否遗漏了一些明显的东西?

[根据第一个答案进行编辑:]

这是编辑 AssemblyInfo.cs 文件的方法:

def replace_assembly_strings(file_path, helper)

    if not (File.exists?(file_path) || File.writable?(file_path))
      raise "the file_path \"#{file_path}\" can not be written to.  Does it exist?"
    end

    path = Pathname.new(file_path)
    contents = path.read
    puts "AssemblyVersion(\"#{helper.build_info.build_number_template}\")"
    contents = contents.gsub(/AssemblyVersion\(\"([\d.*]*)\"\)/, "AssemblyVersion(\"#{helper.build_info.build_number_template}\")")
    contents = contents.gsub(/AssemblyFileVersion\(\"([\d.*]*)\"\)/, "AssemblyFileVersion(\"#{helper.build_info.build_number_template}\")")
    contents = contents.gsub(/AssemblyCompany\(\"(.*)\"\)/, "AssemblyCompany(\"#{helper.build_info.company}\")")
    contents = contents.gsub(/AssemblyCopyright\(\"(.*)\"\)/, "AssemblyCopyright(\"#{helper.build_info.copyright}\")")

    File.open(file_path, 'w') {|f| f.write(contents)}

  end

puts 行输出 AssemblyVersion("1.1.0.62") 但结果文件显示 AssemblyVersion("1.1.0.&gt;")

【问题讨论】:

  • 关于你的更新,看起来helper.build_info.build_number_template 在你第一次和第二次调用它时给你不同的结果。您可能有兴趣尝试调试此代码。这是一个关于设置和使用调试器的链接pivotallabs.com/users/chad/blog/articles/…你也可以去老学校继续使用打印语句(实际上,这是他们在我学校仍然教的)在这种情况下,如果你重复你的多次声明?还是 gsub 前后的 p 内容?
  • 不管出于什么原因,今天早上它可以工作了。我想知道我的 Windows 命令提示符是否发生了一些奇怪的缓存,即使在我编辑了包含文件之后,它也从 rake 命令返回了相同的结果。哦,好吧,无论哪种方式,它现在都有效。感谢您的帮助!

标签: ruby regex rake


【解决方案1】:

Readlines 不会从行尾隐式删除换行符。通常人们会调用 chomp!结果上。您可以使用 p 方法(或调试器,我猜)解决这样的问题,在调用 gsub 之前添加 p line。然后您应该看到(除非我错得离谱)您的版本实际上看起来像 "64:67M\n" 但是,您有一个更简单的解决方案,String#to_i 会将字符串转换为 int 直到找到非数字。所以"64:67M".to_i # =&gt; 64"64:67M\n".to_i # =&gt; 64 这让你不必成为一个正则表达式忍者,并解决你的换行问题。

【讨论】:

  • 这很有趣。输入一些 p 命令来查看调试输出显示正确的数字,但文件输出现在以新的方式被破坏。例如,如果我说:将 "AssemblyVersion(\"#{helper.build_info.build_number_template}\")" 放在我的 .gsub 之前的程序集文件上,它会显示正确的输出。但在书面文件中,它显示版本号为“1.1.0.>”。这个文本框不够漂亮,无法显示,我将编辑问题...
【解决方案2】:

这并不能真正解决您的问题,这里对第二种方法进行了一些重构,使其看起来更像是惯用的 ruby​​。我知道我在学习语言时也是这样写的,但是有很多东西让这个函数看起来像用 ruby​​ 编写的 C# 或 java。

def replace_assembly_strings path, helper
  raise %{the path "#{path}" can not be written to.  Does it exist?} unless File.exists?(path) or File.writable?(path)

  file = Pathname.new(path).read

  methods = {/(AssemblyVersion\(\")[\d.*]*(\"\))/      => helper.build_info.build_number_template, 
             /(AssemblyFileVersion\(\")[\d.*]*(\"\))/  => helper.build_info.build_number_template, 
             /(AssemblyCopyright\(\").*(\"\))/         => helper.build_info.copyright,
             /(AssemblyCompany\(\").*(\"\))/           => helper.build_info.company}

  methods.keys.each do |regex| 
    file.gsub! regex, "\1#{methods[regex]}\2"
  end

  File.open(path, 'w') {|f| f.write(file)}
end

ruby 代码涉及很多个人风格,这正是我的做法。这种东西在我学习的时候对我来说是纯金,所以我将逐步详细说明我为什么要更改我更改的内容。

所以,从顶部开始:)

首先,我从方法签名中删除了括号。作为一般做法,除非您需要,否则不应使用括号,因为过多的标点符号会使内容更难阅读。同样从 file_path 到 path,这只是一个简洁的东西(和个人品味)

接下来,你将永远不会在 ruby​​ 中看到 if notunless 总是被使用。这需要一点时间来适应,但是你在阅读时需要做的布尔代数越少越好。也删除了一些括号(与第一次相同的推理),并将|| 切换为or

当谈到and/or&amp;&amp;/|| 时,我更喜欢前者(回到标点符号这一点)。话虽如此,由于运算符优先级的不同,使用该表单可能会出现一个非常大的问题。假设你有这样的东西

def foo bar
  'foobar!' if bar
end

foobar = foo false || true
# foobar == 'foobar!'

首先发生的是false || true 将评估为true,然后true 被传递到foo。如果我们走另一条路

foobar = foo false or true
# foobar == true ????

首先,false 将被传递给 foofoo 将返回 nil,而 nil 在布尔表达式中被认为是 false,因此 nil or true 最终计算为 true

如您所见,这可能会导致非常奇怪的错误。正因为如此,很多红宝石学家只使用 &&/||专门的形式。就个人而言,我只是尽量记住这个问题,因为我真的很喜欢和/或更好。

关于保护子句的最后一点,我用引号替换了%{...} 语法。在 ruby​​ 中创建字符串文字的方法非常多。正因为如此,总有一种方法可以避免转义引号。

下一次更改只是以简洁的名义。一般来说,我尽量减少使用的变量数量,尽管这也是一种风格。

下一个变化是最大的。

我做的第一件事是更改所有正则表达式,以便在我们希望保持不变的开头和结尾位周围进行分组 (()),并删除围绕我们要更改的内容的分组。我这样做是因为使用 gsub,我们可以获得对另一侧组匹配的任何内容的引用(\1 是第一组,\2 第二组)。这在减少噪音方面有很大帮助,正则表达式已经很难阅读;-)

接下来,我试图解决您基本上以蛮力的方式将相同的操作应用于四个事物。当您发现自己这样做时,如果您将操作与您想要操作的内容分开,通常会使事情变得更加清晰。这里的另一个考虑因素是我们正在处理中等长度的正则表达式,它们本身也很难阅读。

将这些东西放入正则表达式的散列中,用什么替换它会更清楚。所以现在我们可以遍历该哈希并进行替换。

您可能注意到我将gsub 更改为gsub!,并摆脱了分配。一般来说,以! 结尾的方法将是不以! 结尾的方法的变体,但在某种程度上你必须更加注意使用它。在这种情况下,gsub 返回一个带有替换的新字符串,gsub! 执行替换。这里的另一点是,在 ruby​​ 中,字符串是可变的,这与 C# 有细微差别,但允许就地替换之类的事情。

一般来说,大多数差异可以归结为三件事; DRY(不要重复自己)在 ruby​​ 中比在 C# 中更进一步,除非你需要,否则不要使用标点符号,并通过尽可能少的打字来拥抱语言的简洁性(在降低可读性之前)

如果您有任何 cmets/问题,请告诉我,祝您在进一步的红宝石冒险中好运 :)

【讨论】:

  • 这对我的常规 Ruby 编程非常有帮助,谢谢。这确实是我对 Ruby 的第一次尝试,所以 ti 肯定看起来像是由 C# 程序员编写的 :) 但我绝对不想将其视为“做同一件事的不同语法”,而是“以不同的方式”做事。”这门语言有很多内在的优势,我必须花时间以不同的方式解决问题。谢谢!
猜你喜欢
  • 2020-07-31
  • 2019-11-18
  • 2018-09-25
  • 2014-10-23
  • 2018-02-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多