在 Ruby 中嗅出不可预测的字符串中的子字符串的最准确方法是什么?

What is the most accurate way to sniff out substrings in unpredictable strings of words in Ruby?

我正在研究收银机。输入是项目列表,如下所示:

1 table at 92.49
1 chair at 44.59
1 imported rug at 580.99
1 set of imported cups at 83.79

如你所见,"imported"这个词的位置并没有遵循固定的标准,但我希望输出如下(注意"at"这个词也被省略并替换了用冒号):

1 table: 92.49
1 chair: 44.59
1 imported rug: 580.99
1 imported set of cups: 83.79

我通过

做到了这一点
.each do |line|

对于输入文件,并删除 line.split

的 array.first 和 array.last
    getElements = []
    getElements << line.split

    leftSnippet = getElements.first.first

    rightSnippet = getElements.last.last

    itemName = line.delete! leftSnippet + rightSnippet

    sort_Imported = []

      if sort_Imported[0] == "imported"
        itemName = itemName.gsub!(/ imported/, "")
        itemName = itemName[0...-5]

      elsif sort_Imported.include? "imported"
        itemName = itemName.gsub!(/ imported/, "")
        itemName = itemName[0...-4]

      else itemName = itemName[0...-5]
    end

给我留下如下内容:

table at
chair at
imported rug at
set of imported cups at

我写这部分的原因:

sort_Imported = []
sort_Imported << newItemName.split
sort_Imported = sort_Imported.first

    if sort_Imported[0] == "imported"
      itemName = itemName.gsub!(/ imported/, "")
      itemName = itemName[0...-5]

  elsif sort_Imported.include? "imported"
    itemName = itemName.gsub!(/ imported/, "")
    itemName = itemName[0...-5]

  else itemName = itemName[0...-5]
end

...是因为当我添加“:”时发生了一些非常奇怪的事情,最后的价格涉及空格和缺失字符。如下所示:

table :
chair:
imported rug:
imported set of  cup:

-4 和 -5 的混乱让我得到了我想要的数据集结果,但我不喜欢它是如何硬编码的,因为如果我有不同类型的相同项目会出现这样的问题。

所以我想知道我是否做错了,是否有更简单的方法来获取这些子字符串?这是我能够得出的唯一合乎逻辑的结论,因为项目名称的性质是它们实际上可以是任何东西。

您可以使用split剪掉开头和结尾的部分,留着以后用。

然后 join 中间在一起,如果我们看到 "imported" 我们将使用 gsub 将其剪切掉并在开头替换它,捕获字符串的其余部分在正则表达式中使用 () 所以我们可以在替换中使用它们。然后我们只需要输入数量和价格。

lines.each do |ln|
  parts = ln.split
  mid = parts[1..-2].join(' ') # skip quantity(1), and at(-2) price(-1)
  #move around imported
  mid.gsub!(/(.+) (imported )(.+)/, "#{} #{} #{}") 
  #put it all together
  puts "#{parts[0]} #{mid} #{parts[-1]}"
end
itemName.gsub(/ at/, ':').gsub(/set of imported (\w*)/, 'imported set of ')

我会这样做:

lines = [
  '1 table at 92.49',
  '1 chair at 44.59',
  '1 imported rug at 580.99',
  '1 set of imported cups at 83.79',
]

puts lines.map{ |line|
  new_line = line.sub(/ at /, ': ')
  if new_line[' imported ']
    new_line = new_line.split.reject{ |s| s['imported'] }.insert(1, 'imported').join(' ')
  end
  new_line
}
# >> 1 table: 92.49
# >> 1 chair: 44.59
# >> 1 imported rug: 580.99
# >> 1 imported set of cups: 83.79

这是正在发生的事情:

line = '1 set of imported cups at 83.79'

new_line = line.sub(/ at /, ': ') # => "1 set of imported cups: 83.79"
new_line = new_line.split         # => ["1", "set", "of", "imported", "cups:", "83.79"]
  .reject{ |s| s['imported'] }    # => ["1", "set", "of", "cups:", "83.79"]
  .insert(1, 'imported')          # => ["1", "imported", "set", "of", "cups:", "83.79"]
  .join(' ')                      # => "1 imported set of cups: 83.79"

详情如下:

  • 我使用 / at / 因为我只想替换单词 at,而不是恰好匹配的子字符串 'at'。同样,我使用 ' imported ' 来确保我没有找到子字符串。
  • split 在空格处打断字符串,有效地返回每个单词。这使得删除 any/all 出现的 "imported".
  • 变得容易
  • insert(1, 'imported') 在我想要的地方插入 "imported"

最后,您对变量名的使用不符合习惯Ruby。遵循标准或在代码审查中遭受同事的蔑视:

getElements   --> get_elements
leftSnippet   --> left_snippet
rightSnippet  --> right_snippet
itemName      --> item_name
sort_Imported --> sort_imported
newItemName   --> new_item_name