Если вы хотите найти слова, чьи буквы и их частота ограничены данной фразой,
Вы можете создать регулярное выражение, чтобы сделать это для вас:
sentence = "Ziegler's Giant Bar"
# count how many times each letter occurs in the
# sentence (ignoring case, and removing non-letters)
counts = Hash.new(0)
sentence.downcase.gsub(/[^a-z]/,'').split(//).each do |letter|
counts[letter] += 1
end
letters = counts.keys.join
length = counts.values.inject { |a,b| a + b }
# construct a regex that matches upto that many occurences
# of only those letters, ignoring non-letters
# (in a positive look ahead)
length_regex = /(?=^(?:[^a-z]*[#{letters}]){1,#{length}}[^a-z]*$)/i
# construct regexes that matches each letter up to its
# proper frequency (in a positive look ahead)
count_regexes = counts.map do |letter, count|
/(?=^(?:[^#{letter}]*#{letter}){0,#{count}}[^#{letter}]*$)/i
end
# combine the regexes, to form a regex that will only
# match words that are made of a subset of the letters in the string
regex = /#{length_regex}#{count_regexes.join('')}/
# open a big file of words, and find all the ones that match
words = File.open("/usr/share/dict/words") do |f|
f.map { |word| word.chomp }.find_all { |word| regex =~ word }
end
words.length #=> 3182
words #=> ["A", "a", "aa", "aal", "aalii", "Aani", "Ab", "aba", "abaiser", "Abantes",
"Abaris", "abas", "abase", "abaser", "Abasgi", "abate", "abater", "abatis",
...
"ba", "baa", "Baal", "baal", "Baalist", "Baalite", "Baalize", "baar", "bae",
"Baeria", "baetzner", "bag", "baga", "bagani", "bagatine", "bagel", "bagganet",
...
"eager", "eagle", "eaglet", "eagre", "ean", "ear", "earing", "earl", "earlet",
"earn", "earner", "earnest", "earring", "eartab", "ease", "easel", "easer",
...
"gab", "Gabe", "gabi", "gable", "gablet", "Gabriel", "Gael", "gaen", "gaet",
"gag", "gagate", "gage", "gageable", "gagee", "gageite", "gager", "Gaia",
...
"Iberian", "Iberis", "iberite", "ibis", "Ibsenite", "ie", "Ierne", "Igara",
"Igbira", "ignatia", "ignite", "igniter", "Ila", "ilesite", "ilia", "Ilian",
...
"laang", "lab", "Laban", "labia", "labiate", "labis", "labra", "labret", "laet",
"laeti", "lag", "lagan", "lagen", "lagena", "lager", "laggar", "laggen",
...
"Nabal", "Nabalite", "nabla", "nable", "nabs", "nae", "naegate", "naegates",
"nael", "nag", "Naga", "naga", "Nagari", "nagger", "naggle", "nagster", "Naias",
...
"Rab", "rab", "rabat", "rabatine", "Rabi", "rabies", "rabinet", "rag", "raga",
"rage", "rager", "raggee", "ragger", "raggil", "raggle", "raging", "raglan",
...
"sa", "saa", "Saan", "sab", "Saba", "Sabal", "Saban", "sabe", "saber",
"saberleg", "Sabia", "Sabian", "Sabina", "sabina", "Sabine", "sabine", "Sabir",
...
"tabes", "Tabira", "tabla", "table", "tabler", "tables", "tabling", "Tabriz",
"tae", "tael", "taen", "taenia", "taenial", "tag", "Tagabilis", "Tagal",
...
"zest", "zeta", "ziara", "ziarat", "zibeline", "zibet", "ziega", "zieger",
"zig", "zing", "zingel", "Zingiber", "zira", "zirai", "Zirbanit", "Zirian"]
Позитивные запросы позволяют создать регулярное выражение, соответствующее позиции в строке, где совпадает некоторый заданный шаблон, без использования части строки, которая соответствует.
Мы используем их здесь, чтобы сопоставить одну и ту же строку с несколькими шаблонами в одном регулярном выражении.
Позиция совпадает, только если все наши шаблоны совпадают.
Если мы разрешаем бесконечное повторное использование букв исходной фразы (как это сделал Кнут в соответствии с комментарием glenra ), тогда еще проще создать регулярное выражение:
sentence = "Ziegler's Giant Bar"
# find all the letters in the sentence
letters = sentence.downcase.gsub(/[^a-z]/,'').split(//).uniq
# construct a regex that matches any line in which
# the only letters used are the ones in the sentence
regex = /^([^a-z]|[#{letters.join}])*$/i
# open a big file of words, and find all the ones that match
words = File.open("/usr/share/dict/words") do |f|
f.map { |word| word.chomp }.find_all { |word| regex =~ word }
end
words.length #=> 6725
words #=> ["A", "a", "aa", "aal", "aalii", "Aani", "Ab", "aba", "abaiser", "abalienate",
...
"azine", "B", "b", "ba", "baa", "Baal", "baal", "Baalist", "Baalite",
"Baalize", "baar", "Bab", "baba", "babai", "Babbie", "Babbitt", "babbitt",
...
"Britannian", "britten", "brittle", "brittleness", "brittling", "Briza",
"brizz", "E", "e", "ea", "eager", "eagerness", "eagle", "eagless", "eaglet",
"eagre", "ean", "ear", "earing", "earl", "earless", "earlet", "earliness",
...
"eternalize", "eternalness", "eternize", "etesian", "etna", "Etnean", "Etta",
"Ettarre", "ettle", "ezba", "Ezra", "G", "g", "Ga", "ga", "gab", "gabber",
"gabble", "gabbler", "Gabe", "gabelle", "gabeller", "gabgab", "gabi", "gable",
...
"grittiness", "grittle", "Grizel", "Grizzel", "grizzle", "grizzler", "grr",
"I", "i", "iba", "Iban", "Ibanag", "Iberes", "Iberi", "Iberia", "Iberian",
...
"itinerarian", "itinerate", "its", "Itza", "Izar", "izar", "izle", "iztle",
"L", "l", "la", "laager", "laang", "lab", "Laban", "labara", "labba", "labber",
...
"litter", "litterer", "little", "littleness", "littling", "littress", "litz",
"Liz", "Lizzie", "Llanberisslate", "N", "n", "na", "naa", "Naassenes", "nab",
"Nabal", "Nabalite", "Nabataean", "Nabatean", "nabber", "nabla", "nable",
...
"niter", "nitraniline", "nitrate", "nitratine", "Nitrian", "nitrile",
"nitrite", "nitter", "R", "r", "ra", "Rab", "rab", "rabanna", "rabat",
"rabatine", "rabatte", "rabbanist", "rabbanite", "rabbet", "rabbeting",
...
"riteless", "ritelessness", "ritling", "rittingerite", "rizzar", "rizzle", "S",
"s", "sa", "saa", "Saan", "sab", "Saba", "Sabaean", "sabaigrass", "Sabaist",
...
"strigine", "string", "stringene", "stringent", "stringentness", "stringer",
"stringiness", "stringing", "stringless", "strit", "T", "t", "ta", "taa",
"Taal", "taar", "Tab", "tab", "tabaret", "tabbarea", "tabber", "tabbinet",
...
"tsessebe", "tsetse", "tsia", "tsine", "tst", "tzaritza", "Tzental", "Z", "z",
"za", "Zabaean", "zabeta", "Zabian", "zabra", "zabti", "zabtie", "zag", "zain",
...
"Zirian", "Zirianian", "Zizania", "Zizia", "zizz"]