Last active
November 6, 2022 12:55
-
-
Save mug896/f4ea12b8cee4a707edf13fe4b7641496 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* $ gcc -O2 pattern_substitution.c | |
* | |
* $ ./a.out | |
* | |
* Usage: ./a.out 'string' 'pattern' 'replacement' [g](global) | |
* | |
* $ ./a.out 'foo bar zoo' 'foo' 'X' | |
* X bar zoo | |
* # 맞는지 테스트 | |
* $ ./a.out 'foo bar zoo' '*bar' 'X' | |
* X zoo $ str='foo bar zoo' | |
* | |
* $ ./a.out 'foo bar zoo' '[abc][abc]?' 'X' $ echo "${str/[abc][abc]?/X}" | |
* foo X zoo foo X zoo | |
* | |
* $ ./a.out 'foo bar zoo' '[fz]??' 'X' g $ echo "${str//[fz]??/X}" | |
* X bar X X bar X | |
* | |
**/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <stdbool.h> | |
typedef struct begend { | |
const char *beg; | |
const char *end; | |
bool star; | |
} begend_t; | |
bool matchhere(char* restrict str, char* restrict pat, begend_t *be); | |
bool matchstar(char* restrict str, char* restrict pat, begend_t *be) | |
{ | |
for ( int i = 0; str[i] != '\0'; i++) { | |
if (matchhere(str + i, pat, be)) | |
return true; | |
} | |
return false; | |
} | |
bool matchhere(char* restrict str, char* restrict pat, begend_t *be) | |
{ | |
int i = 0, j = 0; | |
for ( ; str[i] != '\0' && pat[j] != '\0'; i++, j++) | |
{ | |
if (pat[j] == '?') | |
continue; | |
else if (pat[j] == '[') { | |
bool match = false; | |
for (j++; pat[j] != '\0' && pat[j] != ']'; j++) | |
if (str[i] == pat[j]) match = true; | |
if (! match) return false; | |
} | |
else if (pat[j] == '*') { | |
be->star = true; | |
if (be->beg == NULL && j == 0) | |
be->beg = str; | |
while (pat[j] == '*') j++; | |
if (pat[j] == '\0') { | |
while (str[i] != '\0') i++; | |
be->end = str + i; | |
return true; | |
} | |
return matchstar(str + i, pat + j, be); | |
} | |
else if (str[i] != pat[j]) | |
return false; | |
} | |
while (pat[j] == '*') j++; | |
if (pat[j] == '\0') be->end = str + i; | |
return (str[i] == '\0' && pat[j] == '\0'); | |
} | |
char* replace(char* str, char* pat, char* rep, bool g) | |
{ | |
if (str[0] == '\0' || pat[0] == '\0') | |
return NULL; | |
begend_t be = { NULL, NULL, false }; | |
char *res = malloc(1); | |
res[0] = '\0'; | |
int rep_l = strlen(rep); | |
int res_l = 0; | |
next:; | |
int i = 0; | |
for ( ; str[i] != '\0'; i++) { | |
matchhere(str + i, pat, &be); | |
if (be.end != NULL) break; | |
} | |
if (be.beg == NULL) be.beg = str + i; | |
if (be.end) { | |
res_l += (be.beg - str) + rep_l + 1; | |
res = realloc(res, res_l); | |
strncat(res, str, be.beg - str); | |
strcat(res, rep); | |
if (g == true && be.star == false) { // "g" 옵션에 의한 여러개 replace 는 | |
str += be.end - str; // 패턴에 "*" (star) 가 없을 경우만 가능 | |
be.beg = be.end = NULL; | |
goto next; | |
} | |
else { | |
res = realloc(res, res_l + strlen(be.end) + 1); | |
strcat(res, be.end); | |
return res; | |
} | |
} | |
else { | |
res = realloc(res, res_l + strlen(str) + 1); | |
strcat(res, str); | |
return res; | |
} | |
} | |
void usage(char *cmd) | |
{ | |
fprintf(stderr, "\nUsage: %s 'string' 'pattern' 'replace' [g](global)\n\n", cmd); | |
exit(1); | |
} | |
int main(int argc, char *argv[]) | |
{ | |
if (argc < 4) usage(argv[0]); | |
bool g = false; | |
if (argc == 5) { | |
if (strcmp(argv[4], "g") == 0) | |
g = true; | |
} | |
char* res = replace(argv[1], argv[2], argv[3], g); | |
if (res != NULL) { | |
puts(res); | |
free(res); | |
} | |
else puts(argv[1]); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment