【问题标题】:selection of line based on the pattern using ruby 2.2使用 ruby​​ 2.2 根据模式选择线
【发布时间】:2019-12-20 09:24:39
【问题描述】:

我有一个名为 regional.txt 的文件,它的数据如下:

shell.SetMyFile "Ranger" 
shell.SetMyErrorFile "Discovery"
shell.SetMyFileEnabled 1 
shell.SetMyLogFileEnabled 1

现在我正在使用 ruby​​ 读取此文件,并尝试将 "shell.SetMyFile""shell.SetMyErrorFile" 中的文本过滤为 Ranger发现

File.readlines("regional.txt").each do |line|
      value1 = line.split(" ")[1] if line.include?("shell.SetMyFile")
      value2 = line.split(" ")[1] if line.include?("shell.SetMyErrorFile ")
      puts value1, value2
end

我的结果是 11 而不是 RangerDiscovery。这是因为包括?考虑 "shell.SetMyFileEnabled""shell.SetMyLogFileEnabled" 的方法。如何将其过滤到所需的结果?

【问题讨论】:

  • 好的,让我知道,我的目的是吸引更广泛的受众

标签: ruby ruby-2.0 ruby-2.2 ruby-2.3.1


【解决方案1】:

快速修复如下:

# Need to declare the variables outside the block,
# so they are not trapped in that scope
value1 = nil
value2 = nil

File.readlines("regional.txt").each do |line|
  # NOTE: added trailing space here:
  if line.include?("shell.SetMyFile ")
    value1 = line.split(" ")[1] 
  end
  if line.include?("shell.SetMyErrorFile ")
    value2 = line.split(" ")[1] 
  end
end

puts value1, value2
# => "Ranger"
# => "Discovery"

您也可以使用正则表达式:

key_vals = File.
  read("regional.txt").
  scan(/\w+\.(\w+)[^\w]+(\w+)/).
  to_h

value1 = key_vals["SetMyFile"]
# => "Ranger"

value2 = key_vals["SetMyErrorFile"]
# => "Discovery"

要解释正则表达式,请考虑shell.SetMyFile "Ranger"

  • \w+:任意数量的字母数字字符,匹配前缀,例如外壳
  • \.:文字句号
  • (\w+):匹配组 1,任意数量的字母数字字符,匹配后缀,例如设置我的文件
  • [^\w]+ 任意数量的非字母数字字符,匹配空格和引号
  • (\w+) 匹配组 2,任意数量的字母数字字符。匹配值字符串,例如游侠

在调用scan 后,你会得到一个嵌套数组:

File.read("regional.txt").scan(/\w+\.(\w+) \"?(\w+)/)
# => [
#   ["SetMyFile", "Ranger"],
#   ["SetMyErrorFile", "Discovery"], 
#   ["SetMyFileEnabled", "1"],
#   ["SetMyLogFileEnabled", "1"]
# ]

你可以在这个上面调用to_h把它变成一个hash,方便按键查找:

【讨论】:

  • 使用 3k 行随机文本文件的双向基准测试(减去 puts),没有正则表达式的速度大约快 4 倍。
  • 是的,不确定。我尝试了 3 个版本的 ruby​​,但速度仍然快 3 到 4 倍。
【解决方案2】:

让我们创建你的文件。

FName = "regional.txt"

File.write FName, <<~END
shell.SetMyFile "Ranger" 
shell.SetMyErrorFile "Discovery"
shell.SetMyFileEnabled 1 
shell.SetMyLogFileEnabled 1
END
  #=> 113

我们得到:

desired_lines = ["shell.SetMyFile", "shell.SetMyErrorFile"]

我了解到您希望打印文件中的某些信息。一般来说,最好将所需信息提取到 Ruby 对象中,然后打印感兴趣的信息。这样,如果您希望在代码中操作生成的对象,则无需更改代码的那部分。

可以将文件的行读入一个数组,选择感兴趣的元素,然后提取感兴趣的信息。但是,逐行读取文件并保存以desired_lines 元素开头的那些行中的感兴趣信息会更有效,这只需要一次通过文件并避免需要构造一个中间数组。您可以使用 IO::foreachEnumerator#with_object 方法来做到这一点:

a = IO.foreach(FName).with_object([]) do |line,arr|
  label, value = line.chomp.delete('"').split
  arr << value if desired_lines.include?(label)
end
  #=> ["Ranger", "Discovery"] 

或者,如果您希望将 "Ranger""Discovery" 绑定到它们对应的行,您可以替换:

arr << [label, value]

arr << value

在这种情况下,返回值将是:

[["shell.SetMyFile", "Ranger"], ["shell.SetMyErrorFile", "Discovery"]] 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-01
    • 1970-01-01
    • 2018-08-16
    • 2020-03-22
    相关资源
    最近更新 更多