Главная · Поиск книг · Поступления книг · Top 40 · Форумы · Ссылки · Читатели

Настройка текста
Перенос строк


    Прохождения игр    
Demon's Souls |#13| Storm King
Demon's Souls |#11| Мaneater part 2
Demon's Souls |#10| Мaneater (part 1)
Demon's Souls |#9| Heart of surprises

Другие игры...


liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня
Rambler's Top100
Образование - Богатырев А. Весь текст 1009.15 Kb

Хрестоматия по программированию на Си в Unix

Предыдущая страница Следующая страница
1 ... 55 56 57 58 59 60 61  62 63 64 65 66 67 68 ... 87
всех реализациях это так!).

7.49.  Обратите внимание, что если мы выделяем класс символов при  помощи  сравнения,
например:

       char ch;
       if( 0300 <= ch && ch < 0340 ) ...;

(в кодировке КОИ-8 это маленькие русские буквы), то мы можем натолкнуться на  следую-
щий  сюрприз:  перед сравнением с целым значение ch приводится к типу int (приведение
также делается при использовании char в качестве аргумента функции).  При этом,  если
у  ch  был  установлен  старший бит (0200), произойдет расширение его во весь старший
байт (расширение знакового бита).  Результатом будет отрицательное целое число! Опыт:

            char c = '\201';    /* = 129 */
            printf( "%d\n", c );

печатается -127. Таким образом, наше сравнение не сработает, т.к. оказывается что  ch
< 0.  Следует подавлять расширение знака:

      if( 0300 <= (ch & 0377) && (ch & 0377) < 0340) ...;

(0377 - маска из 8 бит, она же 0xFF, весь байт), либо объявить

            unsigned char ch;

что означает, что при приведении к int знаковый бит не расширяется.

7.50.  Рассмотрим еще один пример:

А. Богатырев, 1992-95                  - 321 -                              Си в UNIX

    main(){
       char ch;
       /* 0377 - код последнего символа алфавита ASCII */
       for (ch = 0100; ch <= 0377; ch++ )
            printf( "%03o %s\n",
              ch & 0377,
              ch >= 0300 && ch < 0340 ? "yes" : "no" );
    }

Какие неприятности ждут нас здесь?
-    во-первых, когда бит 0200 у ch установлен, в сравнении ch выступает как  отрица-
     тельное целое число (т.к. приведение к int делается расширением знакового бита),
     то есть  у  нас  всегда  печатается  "no".   Это  мы  можем  исправить,  написав
     unsigned char ch, либо используя ch в виде

         (ch & 0377)       или     ((unsigned) ch)

-    во-вторых, рассмотрим сам цикл. Пусть  сейчас  ch =='\377'.  Условие  ch <= 0377
     истинно.  Выполняется оператор ch++.  Но ch - это байт, поэтому операции над ним
     производятся по модулю 0400 (0377 - это  максимальное  значение,  которое  можно
     хранить  в  байте - все биты единицы).  То есть теперь значением ch станет 0. Но
     0 < 0377 и условие цикла верно!  Цикл продолжается; т.е.  происходит  зациклива-
     ние.  Избежать этого можно только описав int ch; чтобы 0377+1 было равно 0400, а
     не 0 (или unsigned int, лишь бы длины переменной хватало, чтобы  вместить  число
     больше 0377).

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

        слово один. слово два. -->
        Слово один. Слово два.

Эта программа может оказаться полезной для преобразования текста, набранного в  одном
регистре, в текст, содержащий буквы обоих регистров.

7.52.  Напишите программу, исправляющую опечатки в словах  (spell  check):  программе
задан список слов; она проверяет - является ли введенное вами слово словом из списка.
Если нет - пытается найти наиболее похожее слово из списка,  причем  если  есть  нес-
колько похожих - выдает все варианты.  Отлавливайте случаи:
-    две соседние буквы переставлены местами: ножинцы=>ножницы;
-    удвоенная буква (буквы): ккаррандаш=>карандаш;
-    потеряна буква: бот=>болт;
-    измененная буква: бинт=>бант;
-    лишняя буква: морда=>мода;
-    буквы не в том регистре - сравните с каждым словом из списка, приводя все  буквы
     к маленьким: сОВОк=>совок;

Надо проверять каждую букву слова. Возможно вам будет удобно  использовать  рекурсию.
Подсказка: для некоторых проверок вам может помочь функция match:

      слово_таблицы = "дом";
      if(strlen(входное_слово) <= strlen(слово_таблицы)+1 &&
      match(входное_слово, "*д*о*м*") ... /* похоже */
            *о*м*           ?дом         дом?
            *д*м*           д?ом
            *д*о*           до?м

Приведем вариант решения этой задачи:

А. Богатырев, 1992-95                  - 322 -                              Си в UNIX

    #include 
    #include 
    #include 

    typedef unsigned char uchar;
    #define ANYCHAR '*'
    /* символ, сопоставляющийся с одной любой буквой */

    static uchar version[120];      /* буфер для генерации вариантов */
    static uchar vv;                /* буква, сопоставившаяся с ANYCHAR */

    /* привести все буквы к одному регистру */
    static uchar icase(uchar c){
            return isupper(c) ? tolower(c) : c;
    }

    /* сравнение строк с игнорированием регистра */
    static int eqi(uchar *s1, uchar *s2 )
    {
            while( *s1 && *s2 ){
                    if( icase( *s1 ) != icase( *s2 ))
                            break;
                    s1++; s2++;
            }
            return ( ! *s1 && ! *s2 ) ? 1 : 0 ;
                                    /* OK : FAIL */
    }

    /* сравнение строк с игнорированием ANYCHAR */
    static strok(register uchar *word, register uchar *pat)
    {
            while( *word && *pat ){
                    if( *word == ANYCHAR){
                            /* Неважно, что есть *pat, но запомним */
                            vv= *pat;
                    } else {
                            if( icase(*pat) != icase(*word) )
                                break;
                    }
                    word++; pat++;
            }
            /* если слова кончились одновременно ... */
            return ( !*word && !*pat) ? 1 : 0;
                                    /* OK : FAIL */
    }

А. Богатырев, 1992-95                  - 323 -                              Си в UNIX

    /* ЛИШНЯЯ БУКВА */
    static int superfluous( uchar *word /* слово для коррекции */
                          , uchar *s    /* эталон */
    ){
            register int i,j,k;
            int reply;
            register len = strlen(word);

            for(i=0 ; i < len ; i++){
                    /* генерим слова , получающиеся удалением одной буквы */
                    k=0;
                    for(j=0 ; j < i ; j++)
                            version[k++]=word[j];
                    for(j=i+1 ; j < len ; j++)
                            version[k++]=word[j];
                    version[k]='\0';
                    if( eqi( version, s )) return 1; /* OK */
            }
            return 0;       /* FAIL */
    }

    /* ПОТЕРЯНА БУКВА */
    static int hole;   /* место, где вставлена ANYCHAR */
    static int lost(uchar *word, uchar *s)
    {
            register int i,j,k;
            register len = strlen(word);

            hole= (-1);
            for(i=0 ; i < len+1 ; i++){
                    k=0;
                    for(j=0 ; j < i ; j++)
                            version[k++]=word[j];
                    version[k++]=ANYCHAR;
                    for(j=i ; j < len ; j++)
                            version[k++]=word[j];
                    version[k]='\0';
                    if( strok( version, s )){
                            hole=i;
                            return 1;       /* OK */
                    }
            }
            return 0;       /* FAIL */
    }

А. Богатырев, 1992-95                  - 324 -                              Си в UNIX

    /* ИЗМЕНИЛАСЬ ОДНА БУКВА (включает случай ошибки регистра) */
    static int changed(uchar *word, uchar *s)
    {
            register int i,j,k;
            register len = strlen(word);

            hole = (-1);
            for(i=0 ; i < len ; i++){
                    k=0;
                    for( j=0 ; j < i ; j++)
                            version[k++]=word[j];
                    version[k++]=ANYCHAR;
                    for( j=i+1 ; j < len ; j++)
                            version[k++]=word[j];
                    version[k]='\0';
                    if( strok( version,s)){
                            hole=i;
                            return 1;       /* OK */
                    }
            }
            return 0;       /* FAIL */
    }

    /* УДВОЕННАЯ БУКВА */
    static int duplicates(uchar *word, uchar *s, int leng)
    {
            register int i,j,k;
            uchar tmp[80];

            if( eqi( word, s )) return 1;      /* OK */

            for(i=0;i < leng - 1; i++)
            /* ищем парные буквы */
                    if( word[i]==word[i+1]){
                            k=0;
                            for(j=0 ; j < i ; j++)
                                    tmp[k++]=word[j];
                            for(j=i+1 ; j < leng ; j++)
                                    tmp[k++]=word[j];
                            tmp[k]='\0';
                            if( duplicates( tmp, s, leng-1) == 1)
                                    return 1;       /* OK */
                    }
            return 0;       /* FAIL */
    }

А. Богатырев, 1992-95                  - 325 -                              Си в UNIX

    /* ПЕРЕСТАВЛЕНЫ СОСЕДНИЕ БУКВЫ */
    static int swapped(uchar *word, uchar *s)
    {
            register int i,j,k;
            register len = strlen(word);

            for(i=0;i < len-1;i++){
                    k=0;
                    for(j=0 ; j < i ; j++)
                            version[k++]=word[j];
                    version[k++]=word[i+1];
                    version[k++]=word[i];
                    for(j=i+2 ; j < len ; j++)
                            version[k++]=word[j];
                    version[k]='\0';
                    if( eqi( version, s))
                            return 1;       /* OK */
            }
            return 0;  /* FAIL */
    }

    uchar *words[] = {
            (uchar *) "bag",
            (uchar *) "bags",
            (uchar *) "cook",
            (uchar *) "cool",
            (uchar *) "bug",
            (uchar *) "buy",
            (uchar *) "cock",
            NULL
    };

    #define Bcase(x, operators)     case x: { operators; } break;

    char *cname[5] = {
            "переставлены буквы",
            "удвоены буквы     ",
            "потеряна буква    ",
            "ошибочная буква   ",
            "лишняя буква      "
    };

А. Богатырев, 1992-95                  - 326 -                              Си в UNIX

    static int spellmatch( uchar *word       /* IN  слово для коррекции */
                         , uchar *words[]    /* IN  таблица допустимых слов */
                         , uchar **indx      /* OUT ответ */
    ){
            int i, code, total = (-1);
            uchar **ptr;

            if(!*word) return -1;

            for(ptr = words; *ptr; ++ptr)
                    if(eqi(word, *ptr)){
                            if(indx) *indx = *ptr;
                            return 0;
                    }
            /* Нет в таблице, нужен подбор похожих */
            for(ptr = words; *ptr; ++ptr){
                    uchar *s = *ptr;
                    int max = 5;
                    for(i=0; i < max; i++){
                            switch( i ){
                            Bcase(0,code = swapped(word, s)                  )
                            Bcase(1,code = duplicates(word, s, strlen(word)) )
                            Bcase(2,code = lost(word, s)                     )
                            Bcase(3,code = changed(word, s)                  )
                            Bcase(4,code = superfluous(word, s)              )
                            }

                            if(code){
                                    total++;
                                    printf("?\t%s\t%s\n", cname[i], s);
                                    if(indx) *indx = s;

                                    /* В случае с дубликатами не рассматривать
Предыдущая страница Следующая страница
1 ... 55 56 57 58 59 60 61  62 63 64 65 66 67 68 ... 87
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 

Реклама