Реализация алгоритма Soundex с использованием C ++ - PullRequest
3 голосов
/ 22 апреля 2009

Проще говоря, алгоритм Soundex превращает серию символов в код. Говорят, что символы, которые выдают одинаковый код Soundex, звучат одинаково.

  • Ширина кода 4 символа
  • Первый символ кода всегда является первым символом слова

Каждый символ в алфавите принадлежит к определенной группе (по крайней мере, в этом примере, и код после этого - это правило, которое я буду придерживаться):

  • b, p, v, f = 1
  • c, g, j, k, q, s, x, z = 2
  • д, т = 3
  • l = 4
  • м, n = 5
  • r = 6
  • Каждая другая буква в алфавите принадлежит группе 0.

Другие известные правила включают в себя:

  • Все буквы, принадлежащие группе 0, игнорируются, ЕСЛИ БЕЗ исчерпаны буквы в указанном слове, в этом случае остальная часть кода заполняется нулями.
  • Один и тот же номер нельзя использовать дважды или более последовательно, поэтому символ игнорируется. Единственным исключением является указанное выше правило с несколькими нулями.

Например, слово «Луч» будет производить следующий код Soundex: R000 (R - первый символ предоставленного слова, a отделен от группы 0, поэтому он игнорируется, y отделен от группы 0, поэтому он игнорируется, больше нет символов, поэтому 3 оставшихся символа в коде - 0).

Я создал функцию, которая передала ему 1) массив из 128 символов, который используется для создания кода Soundex, и 2) пустой массив из 5 символов, который будет использоваться для хранения кода Soundex по завершении функция (и передается по ссылке, как большинство массивов для использования в моей программе).

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

// CREATE A SOUNDEX CODE
// * Parameter list includes the string of characters that are to be converted to code and a variable to save the code respectively.
void SoundsAlike(const char input[], char scode[])
{
    scode[0] = toupper(input[0]); // First character of the string is added to the code

    int matchCount = 1;
    int codeCount = 1;
    while((matchCount < strlen(input)) && (codeCount < 4))
    {
        if(((input[matchCount] == 'b') || (input[matchCount] == 'p') || (input[matchCount] == 'v') || (input[matchCount] == 'f')) && (scode[codeCount-1] != 1))
        {
            scode[codeCount] = 1;
            codeCount++;
        }
        else if(((input[matchCount] == 'c') || (input[matchCount] == 'g') || (input[matchCount] == 'j') || (input[matchCount] == 'k') || (input[matchCount] == 'q') || (input[matchCount] == 's') || (input[matchCount] == 'x') || (input[matchCount] == 'z')) && (scode[codeCount-1] != 2))
        {
            scode[codeCount] = 2;
            codeCount++;
        }
        else if(((input[matchCount] == 'd') || (input[matchCount] == 't')) && (scode[codeCount-1] != 3))
        {
            scode[codeCount] = 3;
            codeCount++;
        }
        else if((input[matchCount] == 'l') && (scode[codeCount-1] != 4))
        {
            scode[codeCount] = 4;
            codeCount++;
        }
        else if(((input[matchCount] == 'm') || (input[matchCount] == 'n')) && (scode[codeCount-1] != 5))
        {
            scode[codeCount] = 5;
            codeCount++;
        }
        else if((input[matchCount] == 'r') && (scode[codeCount-1] != 6))
        {
            scode[codeCount] = 6;
            codeCount++;
        }
        matchCount++;
    }

    while(codeCount < 4)
    {
        scode[codeCount] = 0;
        codeCount++;
    }
    scode[4] = '\0';

    cout << scode << endl;
}

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

Так что я делаю не так? Любая помощь будет принята с благодарностью.

Ответы [ 4 ]

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

вместо

scode[codeCount] = 1;

вы должны написать

scode[codeCount] = '1';

когда вы формируете массив символов, первый фактически является первым символом ascii, а последний - символом 1.

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

Вы вызываете strlen (), не добавив нулевое символьное завершение в строку. Таким образом, возвращаемое значение strlen () может быть чем угодно. Вы могли бы исправить это, заполнив «scode» символами «\ 0», прежде чем начать, хотя было бы лучше иметь отдельный счетчик для этого и просто добавить «\ 0», когда вы закончите.

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

Это на самом деле реализация C, а не C ++. В любом случае, вы уверены, что ваши строки обнуляются? В противном случае strlen не будет работать.

Вот несколько советов, которые облегчат чтение и отладку вашего кода:

  • Преобразование ввода в нижний регистр перед началом. Тест на недопустимые символы.
  • Определите переменную, установите ее для ввода [matchCount] и используйте ее. Это сделает код более читабельным.
  • Я бы порекомендовал заменить операторы if-else на один с переключателем.
  • Приспособить к регистру по умолчанию (ни один из операторов if-else или case не вызывается)
0 голосов
/ 22 апреля 2009

C ++ не поддерживает динамические массивы, которые вы, похоже, пытаетесь использовать. Вам необходимо изучить использование класса std :: string. По сути, ваш цикл становится примерно таким:

void Soundex( const string & input, string & output ) {
   for ( int i = 0; i < input.length(); i++ ) {
       char c = input[i];        // get character from input
       if ( c === .... ) {       // if some decision
            output += 'X';       // add some character to output
       }
       else if ( ..... )  {       // more tests
       }
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...