Как создать подмножество слов для приложения анаграммы (php)?


Я создал приложение для создания анаграмм, создав поле анаграммы в своей базе данных со строчной строкой в алфавитном порядке.

Например, всасывание становится киносту, ухо становится воздушным и так далее.

Что я хочу сделать сейчас, так это создать подслова из исходной анаграммы, которую искали.

Пример: Как бы вы извлекли слова подмножества из поиска для "ареста", т.Е. "отдыха" и "пристального взгляда".

Author: NGLN, 2009-07-02

6 answers

Вот подход, который я использовал раньше, который использует ваш список слов, отсортированных в алфавитном порядке.

1) Возьмите целевое слово (арест) и отсортируйте его (ошибка).

2) Затем из отсортированного слова создайте новые строки, в которых каждая буква либо включена, либо исключена. Для слова из N букв это дает 2**N возможных строк. (Я не знаю PHP, но могу дать вам псевдокод или, например, Python, если хотите.)

Для вашего целевого слова у нас есть: a, e, r, r, s, t, st, rs, rt, первый, rr, rs, rt, первый, rrs, rrt, первый, er, er, es, et, est, ers, ert, erst, err, ers, ert, err, err, err, err, err, errst, ae, ar, ar, как, в, аст, арс, искусство, арст, арр, арр, арр, арр, арр, арр, арр, арр, арр, аэр, аэр, аэр, аэр, аэр, аэр, аэр, аэр, аэр, аэр, аэр, аэр, аэр, аэр, аэр, аэр, аэр, аэр, аэр, аэр, аэр, аэр, аэр, аэр, аэр , аэрт, аэрст, аэррс, аэррт, аэррст

3) Затем проверьте эти строки в своем отсортированном списке. Те, которые отображаются в вашем отсортированном списке, соответствуют нужному вам подмножеству слов.

Например, aerrst соответствует полным анаграммам (арест, редчайший, растр,...)
например, aerst будет в вашем отсортированном списке (пристальный взгляд, слезы,...)
например, rrs не будет в вашем отсортированном списке

 2
Author: jonpalin, 2009-07-03 10:41:12

Включите пробел в конце исходного слова. На каждой итерации, где пробел заканчивается в середине букв, вы получите два слова. Затем вы можете проверить эти два слова. Если пробел находится в начале или конце шаблона итерации, обрежьте его и проверьте это одно слово.

 1
Author: Mark Jones, 2009-07-02 13:22:28

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

CS.

 1
Author: , 2009-07-03 10:22:11

Этот подход немного отличается от вашего, но я считаю, что его будет легко реализовать программно. Я не уверен, что это оптимально с точки зрения производительности, но я оставлю это на ваше усмотрение :-)

Сначала вам понадобится словарь всех юридических слов, которые вы хотите сопоставить.

Создайте таблицу "Словарь" или "Слова" в своей базе данных, в первом столбце которой будет храниться фактическое слово, а во втором - слово, преобразованное в верхний или нижний регистр для удобства сравнение, а затем один столбец целых чисел для каждой буквы алфавита A-Z.

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

Пример слова: бухгалтер

Сохраните слово "бухгалтер" в столбце "слово", 1 в столбцах "b", "p" и "r", 2 в столбцах "o" и "k" и 3 в столбце "e".

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

  • Посчитайте буквы в вашей строке.
  • Составьте SQL-запрос, который вернет все слова из вашей таблицы словарей, в которых не используются буквы, не найденные в данном слове, или в которых больше какой-либо конкретной буквы, чем существует в вашем слове.

Вы могли бы добиться этого, создав массив в памяти с 26 позиции, представляющие алфавит

Примерное слово: транспортное средство

SELECT Word FROM Dictionary WHERE NOT (
  (a >= 1) OR (b >= 1) OR (c >= 2) ... OR (z >= 1)
)

Таким образом, любое слово в вашем словаре, в котором есть "a" или "z", исключается, поскольку запрос отфильтрует любые слова, в которых число "a" или "z" равно хотя бы одному, и любое слово, в котором используется более одного "c", отфильтровывается.

Вы можете легко сгенерировать все условия "ИЛИ" программно, используя массив из 26 целых чисел, все из которых начинаются с 1, а затем просмотреть свое слово, добавив 1 к соответствующее значение массива каждой найденной вами буквы.

ОБНОВЛЕНИЕ - пример кода окончательного подсчета

Простите мой пример кода ниже - он будет написан на ASP (VBScript) - но вы должны быть в состоянии понять и перевести на PHP, или попросите доброго человека сделать это за вас, если нет.

Const AsciiCodeLowerCaseA = 97
InputWord = "Carrots"
LowerCaseInputWord = LCase(InputWord)

Dim LetterCount(26)

for i = 1 to 26
  LetterCount(i) = 1
next

for j = 1 to Len(InputWord)
  CurrentLetter = Mid(InputWord, j, 1)
  AsciiCode = Chr(CurrentLetter)
  AlphabetPos = AsciiCode - AsciiCodeLowerCaseA + 1
  LetterCount(AlphabetPos) = LetterCount(AlphabetPos) + 1
next

Преобразуя каждую букву слова в ее значение ASCII, затем вычитая код ascii для нижнего регистра "a" и добавляя 1, вы получаете положение этой буквы в алфавите от 1 до 26. Теперь вы добавляете 1 к эта позиция в массиве.

Это кажется нелогичным, но инициализируйте все буквы 1 в своем массиве. Когда вы создаете инструкцию SQL, вы удаляете все слова с количеством букв выше, чем у вашего входного слова, поэтому, если буква не отображается в исходном слове, вы отфильтровываете слова, в которых есть одна или несколько таких букв. Если буква появляется один раз, вы отфильтровываете слова, содержащие две или более этих букв, и так далее.

 0
Author: Bork Blatt, 2009-07-02 15:23:25

Привет, Борк. я пытался адаптировать ваш код к PHP, и у меня есть следующее:

$lettercount = массив ("a" => 1, "b" => 1, "c" => 1, "d" => 1, "e" => 0, "f" => 1, "g" => 1, "h" => 1, "i" => 1, "j" => 1, "k" => 1, "l" => 1, "m" => 1, "n" => 1, "o" => 1, "p" => 1, " q" => 1, "r" => 1, "s" => 1, "t" => 1, "u" => 1, "v" => 1, "w" => 1, "x" => 1, "y" => 1, "z" => 1);

$AsciiCodeLowerCaseA = 97;

for ($j = 1; $j < strlen($string); $j++) {
  $CurrentLetter = $string[$j];
  $AsciiCode = ord($CurrentLetter);
  $AlphabetPos = $AsciiCode - $AsciiCodeLowerCaseA + 1;
      $LetterCount[$AlphabetPos] = $LetterCount[$AlphabetPos] + 1;
}

Я жестко закодировал бит объявления массива, чтобы сэкономить время.

В любом случае, похоже, это не сработало и выдал мне эту ошибку: Обратите внимание: Неопределенное смещение: 1

Вот скриншот ошибок, которые я получаю, я также добавил эхо-сигналы для каждого var или массива в цикле, чтобы посмотреть, можете ли вы понять, что происходит.

Http://i42.tinypic.com/11ryz4g.png

Я думаю, что он неправильно идентифицирует букву aplhabet в массиве и, следовательно, неправильно добавляет числа в конец массива.

Дайте мне знать, что, по вашему мнению, я должен сделать.

 0
Author: , 2009-07-03 10:20:26

Энди,

Я думаю, вам нужно преобразовать код ASCII обратно в символ - вы индексируете массив буквами, но обращаетесь к нему со значениями ASCII.

Вот ваш код, слегка измененный:

$lettercount = массив ("a" => 1, "b" => 1, "c" => 1, "d" => 1, "e" => 0, "f" => 1, "g" => 1, "h" => 1, "i" => 1, "j" => 1, "k" => 1, "l" => 1, "m" => 1, "n" => 1, "o" => 1, "p" => 1, " q" => 1, "r" => 1, "s" => 1, "t" => 1, "u" => 1, "v" => 1, "w" => 1, "x" => 1, "y" => 1, "z" => 1);

$AsciiCodeLowerCaseA = 97;

for ($j = **0**; $j < strlen($string); $j++) {
  $CurrentLetter = $string[$j];
  $AsciiCode = ord($CurrentLetter);
  $AlphabetPos = **chr($AsciiCode - $AsciiCodeLowerCaseA + 1);**
  $LetterCount[$AlphabetPos] = $LetterCount[$AlphabetPos] + 1;
}

Также я только что заметил, что вы индексируете символы в строке с 1, но массивы имеют нулевое значение.

Я думаю, что это также может быть намного проще (если только я чего-то не упустил)

for($j = 0; $j < strlen($string); $j++) {
$LetterCount[$string[$j]]++;
}
 0
Author: Rob, 2009-07-03 11:06:00