Skip to content

Instantly share code, notes, and snippets.

@armornick
Created May 22, 2014 11:05
Show Gist options
  • Select an option

  • Save armornick/0be4ca5e687d8e44862c to your computer and use it in GitHub Desktop.

Select an option

Save armornick/0be4ca5e687d8e44862c to your computer and use it in GitHub Desktop.
Replace using POSIX regular expressions
/* replace using posix regular expressions */
/* source: http://www.daniweb.com/software-development/c/code/216955/replace-using-posix-regular-expressions */
#include <stdio.h>
#include <string.h>
#include <regex.h>
int rreplace (char *buf, int size, regex_t *re, char *rp)
{
char *pos;
int sub, so, n;
regmatch_t pmatch [10]; /* regoff_t is int so size is int */
if (regexec (re, buf, 10, pmatch, 0)) return 0;
/* first do preliminary replacements in the replacement text
i.e. \1 -> first match
*/
for (pos = rp; *pos; pos++)
if (*pos == '\\' && *(pos + 1) > '0' && *(pos + 1) <= '9') {
so = pmatch [*(pos + 1) - 48].rm_so;
n = pmatch [*(pos + 1) - 48].rm_eo - so;
if (so < 0 || strlen (rp) + n - 1 > size) return 1;
memmove (pos + n, pos + 2, strlen (pos) - 1);
memmove (pos, buf + so, n);
pos = pos + n - 2;
}
sub = pmatch [1].rm_so; /* no repeated replace when sub >= 0 */
for (pos = buf; !regexec (re, pos, 1, pmatch, 0); ) {
n = pmatch [0].rm_eo - pmatch [0].rm_so;
pos += pmatch [0].rm_so;
if (strlen (buf) - n + strlen (rp) + 1 > size) return 1;
memmove (pos + strlen (rp), pos + n, strlen (pos) - n + 1);
memmove (pos, rp, strlen (rp));
pos += strlen (rp);
if (sub >= 0) break;
}
return 0;
}
int main (int argc, char **argv)
{
char buf [FILENAME_MAX], rp [FILENAME_MAX];
regex_t re;
if (argc < 2) return 1;
if (regcomp (&re, argv [1], REG_ICASE)) goto err;
for (; fgets (buf, FILENAME_MAX, stdin); printf ("%s", buf))
if (rreplace (buf, FILENAME_MAX, &re, strcpy (rp, argv [2])))
goto err;
regfree (&re);
return 0;
err: regfree (&re);
return 1;
}
/**
Note by author:
If you want to test it, just run it in some bash-like shell, giving the regular expressions
and the replace pattern as arguments, preferably in the form $'expression' if you want to use
escape sequences such as \t and \n. Then enter the text, and if your expression is correct, the
the replaced line will appear, end with ctrl-d. In the basic regular expression you can use . for
any character, range or set like [a-z0-9;-] or inverted like [^ ], and * or \{n,m\} for repeated
character, range or subexpression. Subexpression is between \( and \), and you can refer to it with
\n both in expression and replace pattern, where n is the number of subexpression, like in \1. Remember
about *, that regular expression is evaluated from left to right, so the construct like a* must follow
some other characters, and cannot be in the beginning of the expression, because * means none or more,
and construct like a* alone doesn't determine any particular place.
**/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment