2009-08-25 6 views
4

기본 검색/변환 테이블을 C로 구현하고 싶습니다. 즉, 설정 파일에서 한 쌍의 단어 목록을 읽고 런타임에 수신 된 텍스트를 검색하여 찾은 각 소스 단어를 해당 대상 단어로 바꿉니다. 예를 들어, 내 사용자 입력 텍스트는 C에서 문자열 변환 테이블 구현

"Hello world, how are you today?" 

이었고, 내 설정 파일은 함수가

"Hello user, why are you today?" 

내가 겸손한 금액이 할 수 반환 실행

world user 
how why 

했다 tedium (현재 그들은 glib string utility functions을보고 있습니다.)하지만, 일부 라이브러리 나 다른 라이브러리에서 완전히 해결 된 문제라고 생각합니다. 어떤 포인터?

(나는 문제가 합리적으로 homeworky 소리 : 나는, 따라서 순수 C 요구 사항을 libpurple 플러그인을 쓰고 있어요 인정한다하더라도 아니, 이건, 숙제를하지 않습니다.) 당신은 GNU gettext

+0

당신은 당신의 순수한 C에서 sed를 벗길 수 있습니까? –

+0

jamie : 아니, libpurple (즉, pidgin) 플러그인 용이므로 이상적으로 플랫폼에 독립적이어야합니다.현재 진행중인 Perl 플러그인 인터페이스도 있지만, 기본적으로 모든 사람이 컴파일하지는 않습니다. 그래서 나는 순수한 C 언어를 고수하려고합니다. –

+0

저는 (이론적으로 효율적인) 문자열 라이브러리를 측면 프로젝트로 만들고 있습니다. 검사를 위해 제공 하겠지만 현재 인터넷에 아무 것도없고 거의 완성되지 않았습니다. –

답변

5

너무 단순한 문자열 조작 방법을 찾는 것이 얼마나 힘든지에 놀랐습니다. 내가 원했던 것은 객체 지향 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; 
} 
+0

감사합니다 blak3r, 유용한 시작점처럼 보입니다. 문자열 메서드가 부족한 경우, 웹 사이트를 통해 glib를 배울 때 누군가가 실제로 replace() 함수를 문자열 모듈에 추가하고 패치를 완료했으며 일반적으로 그렇지 않다는 근거로 촬영했다고 제안했습니다. 충분히 유용하다! –

0

을 확인할 수 있습니다. Wikipedia article도 참조하십시오.

+0

gettext는 컴파일시에 입력 문자열을 알아야합니다. 나는 런타임에받은 문자열을 번역하고 싶다. 또한 입력 텍스트에서 해당 문자열을 찾아야합니다. 그것은 전혀 다른 문제입니다. –

+0

좋아요, 그건 네 질문에서 나에게 명확하지 않았다. 나는 내 머리 꼭대기에서 아무것도 모릅니다. –

+0

그 점을 지적 해 주셔서 감사합니다; 나는 더 명확하게하기 위해 문제 설명을 편집했다. –

0

GNU C library's regex engine은 어떻습니까?

+0

나는 그것을 보았다. 그러나 strstr이했던 것보다이 특별한 문제에 더 많은 것을 제공하지는 않았다. 그것은 대체물이 아니며, 어쨌든 정확한 문자열 일치를 수행하고 있습니다. libpcre는 그렇게 할 것이지만, 그것은 아주 작은 견과류를위한 거대한 쇠 망치처럼 보입니다. 나는이 정확한 문제가 일부 문자열 라이브러리에 의해 해결되지 않았다는 것에 놀랐다. 나는 여기에 게시하기 전에 인터넷 검색을하면서 비어있는 것을 보냈다. –

1

구성 파일 요구 사항이 없다면, (f) lex가 C 코드를 생성 할 수 있습니다. 그러나 이것은 단어 쌍 목록이 바뀔 때마다 재 컴파일을 의미합니다.

어쩌면 과도 함이지만 링크 된 목록의 노드에 각 단어를 저장할 수 있습니다. 따라서 단어를 섞어서 대체하여 새로운 문장을 만드는 것이 매우 쉽습니다.

+0

연결 목록 아이디어는 대체 단어가 보장 될 경우 정말 좋은 아이디어입니다. –

+0

은 libpurple에서 문자열을 가져오고 문자열을 반환 할 것으로 예상되므로 작동하지 않습니다. 그래도 단어로 나눠서 시작합니다. –