在字符串中查找出现的次数并保留出现的顺序

3

我一直在使用正则表达式来查找字符串中的不同模式,这种方法还可以,但是我失去了出现顺序。

例如,当我检查这个字符串:10£ + 5$ / 4EUR时,我会检查是否有符号和/或ISO代码,并在旁边进行一些额外的工作,最终返回一个数组。但它并没有按照出现顺序排序。

查找所有货币的主要方法

def find_currencies(string)
  currencies = []

  # check symbols
  currencies = currencies + currencies_from_symbol(string) if string =~ /\p{Sc}/
  # check iso codes
  if Currency.iso_codes.any? { |code| string =~ /#{code}/i }
    iso_codes = string.scan(Regexp.new(Currency.iso_codes.join('|'), true))

    currencies = currencies + iso_codes.map { |code| Money::Currency.find(code.downcase.to_sym) }
  end

  currencies
end

从货币符号返回货币的方法

def currencies_from_symbol(string)
  currencies = Money::Currency.all.select do |m|
    string.scan(/\p{Sc}/).include?(m.symbol) && m.priority < 10
  end

  unless currencies.any? { |m| m.id == :usd || m.id == :gbp }
    return currencies
  end

  # Default to USD and GBP
  # TODO: Remove when default can be selected
  currencies.select { |m| m.id == :usd || m.id == :gbp }
end
find_currencies 将返回以下结果:[#<Money::Currency id: usd>, #<Money::Currency id: gbp>, #<Money::Currency id: eur>],这与字符串原始顺序不符。我需要它变成 [gbp, usd, eur]
我真的很感激你的帮助。我目前的想法是同时查找符号和 ISO 代码,以保留出现顺序。但是,当然分开做会更好。

1
货币 = string.scan(/\p{Sc}/).map{ |c| Money::Currency.find_by(symbol: c).where('priority < 10') }“10£ + 5$ / 4€” 应该按照 [gbp, usd, eur] 的顺序排列。 - kiddorails
仅从Money gem的文档中看,您可以尝试require 'money'; Money.assume_from_symbol = true; str.split.map { |s| Money.parse(s) }.compact。我安装了Money并发现Money::new和其他方法可用,但是parse似乎需要安装(某些部分的)Rails。由于我不知道Rails,因此无法测试。(请尝试并在评论中报告结果。)我假设如果字符串无法解析,则parse返回nil。如果它引发异常,则必须捕获并返回nil - Cary Swoveland
@kiddorails 这不是一个 ActiveRecord 类,但我修改了你的方法,看起来可以工作。我还没有测试更复杂的字符串以查看它是否保留顺序。谢谢! - Maxim Fedotov
1
@CarySwoveland Money已经停止支持字符串解析,该功能已转移到Monetize gem中,我正在使用它。但它并不够复杂,还有待探索。 - Maxim Fedotov
1个回答

0

我采用了@kiddorails建议的方法,到目前为止似乎很有效。我还拆分了一些方法,但是使用所有货币符号并进行直接select最终保留了正确的顺序:

symbols    = string.scan(/\p{Sc}/)
currencies = symbols.flat_map { |symbol| find_currency_by_symbol(symbol) }

def find_currency_by_symbol(symbol)
  Money::Currency.all.select do |currency|
    currency.symbol == symbol && currency.priority < 10
  end
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接