реализация таблицы перевода строк в c - PullRequest
4 голосов
/ 25 августа 2009

Я хочу реализовать базовую таблицу поиска / замены в C; то есть он будет читать список пар слов из файла конфигурации и просматривать текст, полученный во время выполнения, заменяя каждое найденное исходное слово соответствующим целевым словом. Например, если мой пользовательский текст был

"Hello world, how are you today?"

и мой файл конфигурации был

world user
how why

выполнение функции вернет

"Hello user, why are you today?"

Я мог бы сделать это с небольшим количеством утомительного (в настоящее время глядя на вспомогательные функции строки glib *, потому что они там есть), но я думаю, что это должно быть полностью решенной проблемой в той или иной библиотеке. Есть указатели?

(Нет, это не домашнее задание, хотя я признаю, что проблема звучит вполне домашне :) Я пишу плагин libpurple, отсюда и требование чистого C).

Ответы [ 4 ]

5 голосов
/ 26 августа 2009

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

Что делает реализацию такого метода сложным, так это то, что приложение действительно решает, каким образом лучше всего выделить буфер для размещения преобразованной версии строки. У вас есть несколько вариантов: 1) Сделайте так, чтобы пользователь передавал буфер приложению и оставлял его на усмотрение пользователя, чтобы буфер всегда был достаточно большим для преобразованной версии. 2) Выполните некоторое динамическое выделение памяти внутри метода и заставьте вызывающую функцию вызывать free () для возвращаемого указателя.

Я выбрал # 1, потому что накладные расходы на динамическое выделение памяти слишком велики для встроенных приложений. Кроме того, это требует от пользователя вызова free () позже, что довольно легко забыть.

Результирующая функция выглядит довольно уродливо. Я сделал очень быструю реализацию, и я включил ее ниже. Этот метод должен быть проверен в дальнейшем перед использованием в производстве. В итоге я взял проект в другом направлении, прежде чем его использовать.

#include <stdio.h>
#include <time.h>
#include <string.h>
#include <assert.h>

/*
 * searches an input string for occurrence of a particular string and replaces it with another.  The resulting string is
 * stored in a buffer which is passed in to the function. 
 * 
 * @param pDest is a buffer which the updated version of the string will be placed into.  THIS MUST BE PREALLOCATED.  It's 
          the callers responsibility to make sure that pDest is of sufficient size that the buffer will not be overflowed.
 * @param pDestLen is the number of chars in pDest
 * @param pSrc is a constant string which is the original string
 * @param pSearch is the string to search for in pSrc.
 * @param pReplacement is the string that pSearch will be replaced with.
 * @return if successful it returns the number of times pSearch was replaced in the string.  Otherwise it returns a negative number
 *         to indicate an error.  It returns -1 if one of the strings passed in == NULL, -2 if the destination buffer is of insufficient size.  
 *         Note: the value stored in pDest is undefined if an error occurs.  
 */
int string_findAndReplace( char* pDest, int pDestLen, const char* pSrc, const char* pSearch, const char* pReplacement) {
    int destIndex=0;
    char* next;
    const char* prev = pSrc;
    int copyLen=0;
    int foundCnt = 0;

    if( pDest == NULL || pDestLen == 0 || pSrc == NULL || pSrc == NULL || pReplacement == NULL ) {
        return -1;
    }

    // TODO: BEFORE EACH MEMCPY, IT SHOULD BE VERIFIED THAT IT WILL NOT COPY OUT OF THE BOUNDS OF THE BUFFER SPACE
    //       THIS IS A VERY BASIC CHECK 
    if( pDestLen < strlen(pSrc) ) {
        return -2;
    }


    memset(pDest, 0x00, pDestLen);

    //printf("Entered findAndReplace\r\n");

    do {    
        next = strstr( prev, pSearch );

        if( next != NULL ) {        
            //printf("  next -> %s\r\n", next);

            copyLen = (next-prev);

            // copy chars before the search string
            memcpy( &pDest[destIndex], prev, copyLen ); 
            destIndex += copyLen;

            // insert the replacement               
            memcpy( &pDest[destIndex], pReplacement, strlen(pReplacement) );
            destIndex += strlen(pReplacement);              

            prev = next;
            prev += strlen(pSearch);
            foundCnt++;         
        }
    }while( next != NULL );

    //copy what's left from prev to the end to the end of dest.
    copyLen = strlen(prev);
    memcpy( &pDest[destIndex], prev, copyLen+1); // +1 makes it null terminate.

    //printf("prev='%s'\r\ndest='%s'\r\n", prev, pDest);
    return foundCnt;
}


// --------- VERY BASIC TEST HARNESS FOR THE METHOD ABOVE --------------- // 

#define NUM_TESTS 8

// Very rudimentary test harness for the string_findAndReplace method.
int main(int argsc, char** argsv) {

int i=0;
char newString[1000];

char input[][1000] = { 
"Emergency condition has been resolved. The all clear has been issued.",
"Emergency condition has been resolved and the all clear has been issued.",
"lions, tigers, and bears",
"and something, and another thing and",
"too many commas,, and, also androids",
" and and and,, and and ",
"Avoid doors, windows and large open rooms.",
"Avoid doors and windows."

};

char output[][1000] = { 
"Emergency condition has been resolved. The all clear has been issued.",
"Emergency condition has been resolved, and the all clear has been issued.",
"lions, tigers,, and bears",
"and something,, and another thing and",
"too many commas,, and, also androids",
", and, and, and,,, and, and, ",
"Avoid doors, windows, and large open rooms.",
"Avoid doors, and windows."
};

    char searchFor[] = " and ";
    char replaceWith[] = ", and ";

    printf("String replacer\r\n");

    for( i=0; i< NUM_TESTS; i++ ) {

        string_findAndReplace( newString, sizeof( newString ), input[i], searchFor, replaceWith );

        if( strcmp( newString, output[i] ) == 0 ) {
            printf("SUCCESS\r\n\r\n");
        }
        else {
            printf("FAILED: \r\n IN :'%s'\r\n OUT:'%s'\r\n EXP:'%s'\r\n\r\n", input[i],newString,output[i]);
        }

    }

    printf("\r\nDONE.\r\n");
    return 0;
}
1 голос
/ 26 августа 2009

Если у вас нет требований к файлу конфигурации, вы можете получить (f) lex для генерации кода на C для вас. Но это будет означать перекомпиляцию каждый раз, когда меняется список пар слов.

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

0 голосов
/ 25 августа 2009

Как насчет движка регулярных выражений библиотеки GNU C ?

0 голосов
/ 25 августа 2009

Вы можете проверить GNU gettext . (Также см. статью в Википедии .)

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