Skip to content

Instantly share code, notes, and snippets.

@mug896
Last active November 6, 2022 12:55
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save mug896/f4ea12b8cee4a707edf13fe4b7641496 to your computer and use it in GitHub Desktop.
/*
* $ 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