Si vous voulez trouver les mots dont ceux-ci sont limités par l'expression donnée lettres et fréquence, vous pouvez construire une regex pour le faire pour vous :
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"]
lookaheads positives vous permettent de faire une expression régulière qui correspond à une position dans la chaîne où un certain modèle spécifié correspond sans consommer la partie de la chaîne qui correspond. Nous les utilisons ici pour faire correspondre la même chaîne à plusieurs motifs dans une seule regex. La position ne correspond que si tous nos motifs correspondent.
Si nous permettons la réutilisation infinie de lettres de la phrase originale (comme Knuth fit selon le commentaire de glenra), alors il est encore plus facile de construire une regex:
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"]
question était ambiguë. Votre résultat après puts() n'était pas clair. Pouvez-vous expliquer plus? – ecleel
La question est clarifiée. –
"peut être formé à partir des lettres dans" est toujours ambigu dans le sens où il n'est pas clair si le remplacement est autorisé. Par exemple: le mot "aa" peut être formé à partir d'un texte incluant la lettre "a", mais seulement si vous êtes autorisé à l'utiliser plus d'une fois. En utilisant/usr/share/dict/words et cette chaîne, je trouve 3182 ou 6725 mots, selon la réponse qui était l'intention. – glenra