regex(3)

๐Ÿ’– regex(3) โ€” the POSIX regex girlies ๐Ÿ’–

okay so bestie, welcome to regex(3), aka the library functions manual for regcomp, regexec, regerror and regfree โ€” your four besties for matching patterns in strings. no cap, this is the whole squad.


โœจ NAME โœจ

regcomp, regexec, regerror, regfree โ€” POSIX regex functions. that's the lineup, that's the group chat. ๐Ÿ’…

๐Ÿ“š LIBRARY ๐Ÿ“š

Standard C library (libc, -lc). she lives in libc, she's literally always there for you. ๐Ÿซถ

๐ŸŽ€ SYNOPSIS ๐ŸŽ€

#include <regex.h>

int regcomp(regex_t *restrict preg, const char *restrict regex,
            int cflags);
int regexec(const regex_t *restrict preg,
            const char *restrict string,
            size_t n, regmatch_t pmatch[_Nullable restrict n],
            int eflags);

size_t regerror(size_t errbuf_size;
            int errcode, const regex_t *_Nullable restrict preg,
            char errbuf[_Nullable restrict errbuf_size],
            size_t errbuf_size);
void regfree(regex_t *preg);

typedef struct {
    size_t    re_nsub;
} regex_t;

typedef struct {
    regoff_t  rm_so;
    regoff_t  rm_eo;
} regmatch_t;

typedef /* ... */  regoff_t;

(yes the regerror sig up there is a little cursed, we're keeping it exactly as-is, it's giving โœจsource fidelityโœจ)


๐ŸŒธ DESCRIPTION ๐ŸŒธ

๐Ÿงš Compilation ๐Ÿงš

regcomp() takes a regular expression and compiles it into a form that's suitable for the subsequent regexec() searches. it's the glow-up phase, basically. ๐Ÿ‘‘

On success, the pattern buffer at *preg is initialized. regex is a null-terminated string. and listen โ€” the locale must be the same when running regexec(). same locale, same vibe, periodt.

After regcomp() succeeds, preg->re_nsub holds the number of subexpressions in regex. so if you pass preg->re_nsub + 1 as n to regexec(), that's sufficient to capture all matches. iconic math honestly.

cflags is the bitwise OR of zero or more of the following:

  • REG_EXTENDED โ€” use POSIX Extended Regular Expression syntax when interpreting regex. if it's not set, POSIX Basic Regular Expression syntax is used instead. two different energies, pick your fighter.
  • REG_ICASE โ€” do not differentiate case. subsequent regexec() searches using this pattern buffer will be case insensitive. she does NOT care about your capital letters, lowercase era fr fr.
  • REG_NOSUB โ€” report only overall success. regexec() will use only pmatch for REG_STARTEND, ignoring n. she's just here for the yes/no, she's not doing detail work.
  • REG_NEWLINE โ€” okay this one has layers, let's unpack:
    • Match-any-character operators don't match a newline. ๐Ÿšซ
    • A nonmatching list ([^...]) not containing a newline does not match a newline.
    • Match-beginning-of-line operator (^) matches the empty string immediately after a newline, regardless of whether eflags, the execution flags of regexec(), contains REG_NOTBOL.
    • Match-end-of-line operator ($) matches the empty string immediately before a newline, regardless of whether eflags contains REG_NOTEOL.

๐Ÿ” Matching ๐Ÿ”

regexec() is used to match a null-terminated string against the compiled pattern buffer in *preg, which must have been initialized with regcomp(). (no shortcutting bestie, you gotta compile first.)

eflags is the bitwise OR of zero or more of the following flags:

  • REG_NOTBOL โ€” the match-beginning-of-line operator always fails to match (but see the compilation flag REG_NEWLINE above ๐Ÿ‘€). this flag may be used when different portions of a string are passed to regexec() and the beginning of the string should not be interpreted as the beginning of the line. tl;dr: it's a chunk, not a fresh start.
  • REG_NOTEOL โ€” the match-end-of-line operator always fails to match (but see the compilation flag REG_NEWLINE above ๐Ÿ‘€).
  • REG_STARTEND โ€” match [string + pmatch[0].rm_so, string + pmatch[0].rm_eo) instead of [string, strnul(string)). this allows matching embedded NUL bytes, which is lowkey powerful. if any matches are returned (REG_NOSUB wasn't passed to regcomp(), the match succeeded, and n > 0), they overwrite pmatch as usual, and the match offsets remain relative to string (not string + pmatch[0].rm_so). this flag is a BSD extension, not present in POSIX. she's a guest star, not main cast.

๐Ÿ“ Match offsets ๐Ÿ“

Unless REG_NOSUB was passed to regcomp(), it is possible to obtain the locations of matches within string: regexec() fills n elements of pmatch with results: pmatch[0] corresponds to the entire match, pmatch[1] to the first subexpression, etc. if there were more matches than n, they are discarded; if fewer, the unused elements of pmatch are filled with -1s. (ghosted with a -1, brutal but honest ๐Ÿ’€)

Each returned valid (non--1) match corresponds to the range [string + rm_so, string + rm_eo).

regoff_t is a signed integer type capable of storing the largest value that can be stored in either an ptrdiff_t type or a ssize_t type. big container energy.

๐Ÿ˜ญ Error reporting ๐Ÿ˜ญ

regerror() is used to turn the error codes that can be returned by both regcomp() and regexec() into error message strings. she's the translator, she turns numbers into actual sentences you can read.

If preg isn't a null pointer, errcode must be the latest error returned from an operation on preg. don't be bringing me stale error codes, i will know.

If errbuf_size isn't 0, up to errbuf_size bytes are copied to errbuf; the error string is always null-terminated, and truncated to fit. always null-terminated bestie, it's the law.

๐Ÿฆ‹ Freeing ๐Ÿฆ‹

regfree() deinitializes the pattern buffer at *preg, freeing any associated memory. and *preg must have been initialized via regcomp(). you can't free what you never compiled, that's not a thing.


๐ŸŒˆ RETURN VALUE ๐ŸŒˆ

  • regcomp() returns zero for a successful compilation or an error code for failure. zero = slay, anything else = we have a problem.
  • regexec() returns zero for a successful match or REG_NOMATCH for failure.
  • regerror() returns the size of the buffer required to hold the string. she tells you how much room she needs, so polite.

๐Ÿ’€ ERRORS ๐Ÿ’€

The following errors can be returned by regcomp():

  • REG_BADBR โ€” invalid use of back reference operator.
  • REG_BADPAT โ€” invalid use of pattern operators such as group or list.
  • REG_BADRPT โ€” invalid use of repetition operators such as using '*' as the first character. girl you can't start with a *, that's not how this works ๐Ÿ˜ญ
  • REG_EBRACE โ€” un-matched brace interval operators.
  • REG_EBRACK โ€” un-matched bracket list operators.
  • REG_ECOLLATE โ€” invalid collating element.
  • REG_ECTYPE โ€” unknown character class name.
  • REG_EEND โ€” nonspecific error. this is not defined by POSIX. she's mysterious, she's undefined, she's giving enigma.
  • REG_EESCAPE โ€” trailing backslash.
  • REG_EPAREN โ€” un-matched parenthesis group operators.
  • REG_ERANGE โ€” invalid use of the range operator; for example, the ending point of the range occurs prior to the starting point. backwards range, backwards behaviour.
  • REG_ESIZE โ€” compiled regular expression requires a pattern buffer larger than 64 kB. this is not defined by POSIX.
  • REG_ESPACE โ€” the regex routines ran out of memory. ๐Ÿ’€
  • REG_ESUBREG โ€” invalid back reference to a subexpression.

๐Ÿ‘‘ ATTRIBUTES ๐Ÿ‘‘

for an explanation of the terms used in this section, see attributes(7).

  • regcomp(), regexec() โ€” Thread safety: MT-Safe locale
  • regerror() โ€” Thread safety: MT-Safe env
  • regfree() โ€” Thread safety: MT-Safe

โญ STANDARDS โญ

POSIX.1-2008.

๐Ÿ•ฐ๏ธ HISTORY ๐Ÿ•ฐ๏ธ

POSIX.1-2001.

Prior to POSIX.1-2008, regoff_t was required to be capable of storing the largest value that can be stored in either an off_t type or a ssize_t type. they changed the requirements, character development arc honestly.


โš ๏ธ CAVEATS โš ๏ธ

re_nsub is only required to be initialized if REG_NOSUB wasn't specified, but all known implementations initialize it regardless. so like, technically optional, practically always there. iykyk.

Both regex_t and regmatch_t may (and do) have more members, in any order. always reference them by name. do NOT assume the layout bestie, that's how you get humbled. ๐Ÿ™ˆ


โœจ EXAMPLES โœจ

#include <stdcountof.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <regex.h>

static const char *const str =
        "1) John Driverhacker;\n2) John Doe;\n3) John Foo;\n";
static const char *const re = "John.*o";

int main(void)
{
    static const char *s = str;
    regex_t     regex;
    regmatch_t  pmatch[1];
    regoff_t    off, len;

    if (regcomp(&regex, re, REG_NEWLINE))
        exit(EXIT_FAILURE);

    printf("String = \"%s\"\n", str);
    printf("Matches:\n");

    for (unsigned int i = 0; ; i++) {
        if (regexec(&regex, s, countof(pmatch), pmatch, 0))
            break;

        off = pmatch[0].rm_so + (s - str);
        len = pmatch[0].rm_eo - pmatch[0].rm_so;
        printf("#%u:\n", i);
        printf("offset = %jd; length = %jd\n", (intmax_t) off,
                (intmax_t) len);
        printf("substring = \"%.*s\"\n", len, s + pmatch[0].rm_so);

        s += pmatch[0].rm_eo;
    }

    exit(EXIT_SUCCESS);
}

๐Ÿซถ SEE ALSO ๐Ÿซถ

grep(1), regex(7)

The glibc manual section, Regular Expressions


and that's the whole page bestie!! ๐ŸŽ€ this one came from the Linux man-pages 6.20, dated 2026-02-22, and it's regex(3) โ€” go forth and match some patterns, you've got this ๐Ÿ’–โœจ๐Ÿฆ‹

๐Ÿ“ฆ where this page comes from
  • arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
  • nixpkgs unstable: man-pages 6.20
  • ๐Ÿ“œ the page's license: Linux-man-pages-copyleft
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms