【问题标题】:How can I parse a string that contains wildcards and character classes in Ruby?如何在 Ruby 中解析包含通配符和字符类的字符串?
【发布时间】:2010-10-21 01:17:34
【问题描述】:

我想编写一个脚本,它接受一个可能如下所示的参数:

abc(ag)de*

a、b、c 是文字字符。

(ag) 表示“'a' 或 'g'”。

* 表示任意一个字母或数字。

我希望脚本创建一个包含输入可以表示的所有可能字符串的数组。 (目的是检查它们是否有可用的域名。)

输入也可以是 abc(ag)de(mnlop) 之类的东西,其中不止一个字符类。

似乎第一个任务是将其拆分为一个或多个数组,所以第一个示例是...

[
  ['a'],
  ['b'],
  ['c'],
  ['a', 'g'],
  ['d'],
  ['e'],
  [
    'a', 'b', 'c', 'd', 'e', 'f', 'g',
    # etc...
  ]
]

这就是我卡住的地方。我不知道如何把它分成那样的部分。

关于如何处理它的任何建议?

【问题讨论】:

  • 标题中“a”和“that”之间缺少一个单词。我不确定正确的词是什么(“字符串”?),所以你应该修复它;)
  • 您可能会发现我在 stackoverflow.com/questions/710670/… 发布的 C# 答案很有帮助。在您的情况下,数组将是您已经为第一个任务生成的数组。基本的递归算法应该相对容易转换为您的问题的解决方案。但我不认识 Ruby,所以我把它留给你或其他人。

标签: ruby parsing


【解决方案1】:

这是一个非常紧凑的解决方案。它绝不会针对性能进行优化,这会对您提供的模式施加一些限制,例如太多的通配符可能不是最好的主意。

这是代码

input1 = "abc(ag)de*"
input2 = "abc(ag)de(mnlop)"

class Array
  def append_suffixes!(suffixes)
    self.replace suffixes.map { |a| self.map { |p| p + a }}.flatten
  end
end

def generate_combinations(pattern)
  combinations = [""]
  pattern.scan(/\(([^)]+)\)|(\*)|(\w+)/) do |group,wildcard,other|
    new_suffixes = case
      when group    : group.split('')
      when wildcard : [*'a'..'z']
      when other    : other
      else raise "Unknown match!"
    end
    combinations.append_suffixes! new_suffixes
  end
  combinations
end

p generate_combinations(input1)
p generate_combinations(input2)
p generate_combinations("**").size

运行上述代码的输出为(稍作修改):

["abcadea", "abcgdea", "abcadeb", "abcgdeb", "abcadec", 
 "abcgdec", "abcaded", "abcgded", "abcadee", "abcgdee", 
 "abcadef", "abcgdef", "abcadeg", "abcgdeg", "abcadeh", 
 "abcgdeh", "abcadei", "abcgdei", "abcadej", "abcgdej", 
 "abcadek", "abcgdek", "abcadel", "abcgdel", "abcadem", 
 "abcgdem", "abcaden", "abcgden", "abcadeo", "abcgdeo", 
 "abcadep", "abcgdep", "abcadeq", "abcgdeq", "abcader", 
 "abcgder", "abcades", "abcgdes", "abcadet", "abcgdet", 
 "abcadeu", "abcgdeu", "abcadev", "abcgdev", "abcadew", 
 "abcgdew", "abcadex", "abcgdex", "abcadey", "abcgdey", 
 "abcadez", "abcgdez"]

["abcadem", "abcgdem", "abcaden", "abcgden", "abcadel", 
 "abcgdel", "abcadeo", "abcgdeo", "abcadep", "abcgdep"]

676 # The number of two letter words i.e. 26*26

如果您对上述代码有任何疑问,请随时询问。

【讨论】:

    【解决方案2】:

    如果您的 * 仅表示单个字符,那么我想这至少是可以解决的。如果它表示“任何字符的零个或多个”,那么感觉就像您的解决方案空间接近于无限,因此很难将其作为实际的具体值返回。

    我想我会通过以某种方式拆分变量部分来解决这个问题,计算出每个变量支持多少个变量,然后(从概念上)以嵌套方式循环所有变量,为最内层循环的每次迭代形成一个输出字符串.

    对于“abc(ag)de*”的示例字符串,这可以归结为(Python-ish 伪代码,我的 Ruby 不供公众使用):

    results = []
    for x in "ag":
      for y in "abcdefghijklmnopqrstuvwxyz":
        results.append("abc%sde%s" % (x, y))
    

    最后一行字符串中的 %s 是一个格式说明符,s 仅表示“字符串”,并将导致字符串后 % 运算符右侧的元组中的相应值插入到该位置。

    【讨论】:

    • 星号表示只有一个字符。
    【解决方案3】:

    您实际上要求的是获取一个正则表达式并生成它匹配的所有字符串。

    那是Ruby Quiz #143。查看左侧的解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-04
      • 2020-04-28
      • 1970-01-01
      • 2013-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多