Невозможно объединить английские слова из букв Ruby - PullRequest
1 голос
/ 09 мая 2009

Мне нужно найти все английские слова, которые можно составить из букв в строке

 sentence="Ziegler's Giant Bar"

Я могу сделать массив букв по

 sentence.split(//)  

Как я могу сделать более 4500 английских слов из предложения в рубине? [править]

Лучше всего разбить проблему на части:

  1. сделать только массив слов с 10 буквами или меньше
  2. длинные слова можно искать отдельно

Ответы [ 4 ]

8 голосов
/ 18 мая 2009

[Предполагая, что вы можете повторно использовать исходные буквы в одном слове]: для каждого слова в вашем словаре составьте два массива букв - один для слова-кандидата и один для входной строки. Вычтите входной массив букв из слова массив букв, и если не осталось никаких букв, вы получите совпадение. Код для этого выглядит следующим образом:

def findWordsWithReplacement(sentence)
    out=[]
    splitArray=sentence.downcase.split(//)
    `cat /usr/share/dict/words`.each{|word|
        if (word.strip!.downcase.split(//) - splitArray).empty?
            out.push word
        end
     }
     return out
end

Вы можете вызвать эту функцию из отладчика irb следующим образом:

output=findWordsWithReplacement("some input string"); puts output.join(" ")

... или вот обертка, которую вы можете использовать для интерактивного вызова функции из скрипта:

puts "enter the text."
ARGF.each {|line|
    puts "working..."
    out=findWordsWithReplacement(line)
    puts out.join(" ")
    puts "there were #{out.size} words."
}

При запуске этого на Mac вывод выглядит так:

$ ./findwords.rb
введите текст.
Гигантский бар Зиглера
работает ...
Аа аа aal aalii Aani Ab aba abaiser абалитовать абантес абарис абас абасе Абасер Абасги Абасин Абасин ослаблять абатис абатис абазе абб абба Аббас Аббаси Аббасси Аббатство Аббесс Абби Абэ abear Абель Абеле Абелия Абелево Абелите Абелите Абелтри Аберрант аберрант абер абетт абеттал Аби Абис абиетате абиетене абиетин Abietineae Abiezer Abigail Абигайль abigeat abilla abintestate
[....]
Z z За Забеян Забета Забиан Забра Забти Zabtie Zag Zain Zan Zanella Zant Zante Zanzalian Zanze Zanzibari ZAR Zaratite Зареба Зат Зати Заттаре Зеа рвение ревность ревность зебра зебра Зебрина зебрине зее зейн зейст зель Zelanian Zeltinger Zen Zenaga zenana Зер Зест Зета Зиара Зиарат Зибелайн зибет зига зигер зиг зигзаг Zigzagger Zilla Zing Zingel Zingiber Zingiberene Zinnia Zinsang Zinzar Zira zirai Zirbanit Zirian Zirianian Zizania Zizia zizz
было 6725 слов.

Это более 4500 слов, но это потому, что словарь Mac достаточно большой. Если вы хотите точно воспроизвести результаты Кнута, скачайте и разархивируйте словарь Кнута отсюда: http://www.packetstormsecurity.org/Crackers/wordlists/dictionaries/knuth_words.gz и замените «/ usr / share / dict / words» на путь, куда вы распаковали замещающий каталог. Если вы все сделали правильно, вы получите 4514 слов, заканчивающихся в этой коллекции:

zanier zanies zaniness Zanzibar zazen ревность зебра зебры Zeiss Zeitgeist Zen Zennist Zest Zestier Zeta Ziegler Zig зигзаг зигзаг зигзаг зигзаги зинг Zingier Zings Zinnia

Полагаю, это отвечает на первоначальный вопрос.

В качестве альтернативы, спрашивающий / читатель, возможно, хотел бы перечислить все слова, которые можно построить из строки без повторного использования любой из вводимых букв. Мой предложенный код для выполнения этого работает следующим образом: Скопируйте слово-кандидат, затем для каждой буквы во входной строке деструктивно удалите первый экземпляр этой буквы из копии (используя «slice!»). Если этот процесс поглощает все буквы, примите это слово.

def findWordsNoReplacement(sentence)
    out=[]
    splitInput=sentence.downcase.split(//)
    `cat /usr/share/dict/words`.each{|word|
        copy=word.strip!.downcase
        splitInput.each {|o| copy.slice!(o) }
        out.push word if copy==""
     }
     return out
end
3 голосов
/ 09 мая 2009

Если вы хотите найти слова, чьи буквы и их частота ограничены данной фразой, Вы можете создать регулярное выражение, чтобы сделать это для вас:

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"]
1 голос
/ 09 мая 2009

Вы можете получить массив букв примерно так:

sentence = "Ziegler's Giant Bar"
letters = sentence.split(//)
1 голос
/ 09 мая 2009

Не думаю, что в Ruby есть словарь английского языка. Но вы могли бы попытаться сохранить все перестановки исходной строки в массиве и проверить эти строки в Google? Скажите, что слово на самом деле есть слово, если оно имеет более 100 000 обращений или что-то в этом роде?

...