Как я могу разобрать строку, которая содержит символы подстановки и классы символов в Ruby? - PullRequest
0 голосов
/ 22 апреля 2009

Я хотел бы написать скрипт, который принимает один аргумент, который может выглядеть следующим образом:

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...
  ]
]

Это то место, где я застреваю. Я не знаю, как разбить его на куски вот так.

Есть предложения, как к нему подойти?

Ответы [ 3 ]

5 голосов
/ 22 апреля 2009

Вот довольно компактное решение. Он никоим образом не оптимизирован для производительности, что накладывает некоторые ограничения на шаблоны, которые вы предоставляете, например. слишком много символов подстановки, вероятно, не лучшая идея.

Вот код

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

Пожалуйста, не стесняйтесь спрашивать, если у вас есть какие-либо вопросы по поводу кода выше.

1 голос
/ 22 апреля 2009

По сути, вы запрашиваете регулярное выражение и генерируете все строки, которые ему соответствуют.

Это было Ruby Quiz # 143 . Посмотрите на решения с левой стороны.

1 голос
/ 22 апреля 2009

Если ваш * означает только один символ, то, я думаю, это как минимум решаемо. Если это означает «ноль или более любого символа», то кажется, что пространство вашего решения граничит с бесконечностью, и, следовательно, его будет трудно вернуть в качестве фактического конкретного значения.

Я думаю, что я бы подошел к этому, как-то разделив переменные части, выяснив, сколько вариантов поддерживает каждый из них, а затем (концептуально) перебрал все переменные вложенным способом, сформировав одну выходную строку для каждой итерации самого внутреннего цикла .

Для примера строки "abc (ag) de *" это будет сводиться к следующему (псевдокод Python-ish, мой Ruby не предназначен для публичного использования):

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

% s в строке в последней строке является спецификатором формата, s просто означает «строку» и вызовет соответствующее значение из кортежа справа от оператора% после того, как строка будет интерполирована в этой позиции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...