REGCOMP(3POSIX)
okay bestie, we're deep in the POSIX Programmer's Manual right now and today's page is REGCOMP(3POSIX) โ the one that explains how the whole regcomp / regexec / regerror / regfree squad works. buckle up, it's a long one, but it's so worth it. ๐
โจ PROLOG โจ
real talk before we even start: this manual page is part of the POSIX Programmer's Manual. that means the Linux implementation of this interface may differ โ so if you're on Linux, go check the corresponding Linux manual page for the actual Linux behavior. also possible: the interface just straight up isn't implemented on Linux at all. ๐ iykyk.
๐ NAME ๐
regcomp, regerror, regexec, regfree โ regular expression matching, the whole girl group. ๐
๐ฆ SYNOPSIS ๐ฆ
#include <regex.h>
int regcomp(regex_t *restrict preg, const char *restrict pattern,
int cflags);
size_t regerror(int errcode, const regex_t *restrict preg,
char *restrict errbuf, size_t errbuf_size);
int regexec(const regex_t *restrict preg, const char *restrict string,
size_t nmatch, regmatch_t pmatch[restrict], int eflags);
void regfree(regex_t *preg);
๐ธ DESCRIPTION ๐ธ
so these functions interpret basic and extended regular expressions, exactly as described in the Base Definitions volume of POSIX.1โ2017, Chapter 9, Regular Expressions. no cap.
๐ the regex_t struct
the regex_t structure is defined in <regex.h> and contains at least this member:
size_tre_nsubโ number of parenthesized subexpressions.
๐ the regmatch_t struct
the regmatch_t structure is defined in <regex.h> and contains at least these members:
regoff_trm_soโ byte offset from start ofstringto start of substring.regoff_trm_eoโ byte offset from start ofstringof the first character after the end of substring.
โจ regcomp() โ the compiler girlie โจ
regcomp() shall compile the regular expression sitting in the string pointed to by the pattern argument, and place the results into the structure pointed to by preg. ๐ซถ
the cflags argument is the bitwise-inclusive OR of zero or more of the following flags, all defined in the <regex.h> header:
REG_EXTENDEDโ use Extended Regular Expressions.REG_ICASEโ ignore case in match (see the Base Definitions volume of POSIX.1โ2017, Chapter 9, Regular Expressions).REG_NOSUBโ report only success/fail inregexec().REG_NEWLINEโ change the handling of<newline>characters, as described in the text.
the default regular expression type for pattern is a Basic Regular Expression. if the application wants Extended Regular Expressions, it specifies that with the REG_EXTENDED cflags flag. periodt.
if the REG_NOSUB flag was not set in cflags, then regcomp() shall set re_nsub to the number of parenthesized subexpressions (delimited by "\(\)" in basic regular expressions or "()" in extended regular expressions) found in pattern. ๐ซ
๐ฅ regexec() โ the matchmaker ๐ฅ
regexec() compares the null-terminated string specified by string with the compiled regular expression preg, which was initialized by a previous call to regcomp().
- if it finds a match,
regexec()shall return0๐ - otherwise, it shall return non-zero โ which means either no match or an error. ๐ญ
the eflags argument is the bitwise-inclusive OR of zero or more of the following flags, all defined in the <regex.h> header:
REG_NOTBOLโ the first character of the string pointed to bystringis not the beginning of the line. therefore, the<circumflex>character ('^'), when taken as a special character, shall not match the beginning ofstring.REG_NOTEOLโ the last character of the string pointed to bystringis not the end of the line. therefore, the<dollar-sign>('$'), when taken as a special character, shall not match the end ofstring.
๐ filling in pmatch
if nmatch is 0, or REG_NOSUB was set in the cflags argument to regcomp(), then regexec() shall ignore the pmatch argument entirely.
otherwise, the application shall ensure that the pmatch argument points to an array with at least nmatch elements, and regexec() shall fill in the elements of that array with offsets of the substrings of string that correspond to the parenthesized subexpressions of pattern:
pmatch[i].rm_soshall be the byte offset of the beginningpmatch[i].rm_eoshall be one greater than the byte offset of the end of substringi
(subexpression i begins at the ith matched open parenthesis, counting from 1.)
offsets in pmatch[0] identify the substring that corresponds to the entire regular expression. unused elements of pmatch up to pmatch[nmatch-1] shall be filled with -1. and if there are more than nmatch subexpressions in pattern (pattern itself counts as a subexpression), then regexec() shall still do the match, but shall record only the first nmatch substrings. not me being limited by my own array ๐ญ
๐ง which substrings get reported โ the rules
when matching a basic or extended regular expression, any given parenthesized subexpression of pattern might participate in the match of several different substrings of string, or it might not match any substring even though the pattern as a whole did match. so here's how we decide which substrings to report in pmatch:
- if subexpression
iin a regular expression is not contained within another subexpression, and it participated in the match several times, then the byte offsets inpmatch[i]shall delimit the last such match. - if subexpression
iis not contained within another subexpression, and it did not participate in an otherwise successful match, the byte offsets inpmatch[i]shall be-1. a subexpression does not participate in the match when:'*'or"\{\}"appears immediately after the subexpression in a basic regular expression, or'*','?', or"{}"appears immediately after the subexpression in an extended regular expression, and the subexpression did not match (matched 0 times)
or:
'|'is used in an extended regular expression to select this subexpression or another, and the other subexpression matched.
- if subexpression
iis contained within another subexpressionj, andiis not contained within any other subexpression that is contained withinj, and a match of subexpressionjis reported inpmatch[j], then the match or non-match of subexpressionireported inpmatch[i]shall be as described in 1. and 2. above, but within the substring reported inpmatch[j]rather than the whole string. the offsets inpmatch[i]are still relative to the start ofstring. - if subexpression
iis contained in subexpressionj, and the byte offsets inpmatch[j]are-1, then the pointers inpmatch[i]shall also be-1. - if subexpression
imatched a zero-length string, then both byte offsets inpmatch[i]shall be the byte offset of the character or null terminator immediately following the zero-length string.
โ ๏ธ if, when regexec() is called, the locale is different from when the regular expression was compiled, the result is undefined. bestie. do not do this. ๐
๐ REG_NEWLINE and the whole newline situation ๐
if REG_NEWLINE is not set in cflags, then a <newline> in pattern or string shall be treated as an ordinary character. simple. iconic.
if REG_NEWLINE is set, then <newline> shall be treated as an ordinary character except as follows:
- a
<newline>instringshall not be matched by a<period>outside a bracket expression, or by any form of a non-matching list (see the Base Definitions volume of POSIX.1โ2017, Chapter 9, Regular Expressions). - a
<circumflex>('^') inpattern, when used to specify expression anchoring (see the Base Definitions volume of POSIX.1โ2017, Section 9.3.8, BRE Expression Anchoring), shall match the zero-length string immediately after a<newline>instring, regardless of the setting ofREG_NOTBOL. - a
<dollar-sign>('$') inpattern, when used to specify expression anchoring, shall match the zero-length string immediately before a<newline>instring, regardless of the setting ofREG_NOTEOL.
๐ regfree() โ the cleanup bestie ๐
regfree() frees any memory allocated by regcomp() associated with preg. that's it. that's the whole function. she's simple, she's necessary, she's serving. โจ
๐ error return values ๐
the following constants are defined as the minimum set of error return values โ though other errors listed as implementation extensions in <regex.h> are possible too:
REG_BADBRโ content of"\{\}"invalid: not a number, number too large, more than two numbers, first larger than second.REG_BADPATโ invalid regular expression.REG_BADRPTโ'?','*', or'+'not preceded by valid regular expression.REG_EBRACEโ"\{\}"imbalance.REG_EBRACKโ"[]"imbalance.REG_ECOLLATEโ invalid collating element referenced.REG_ECTYPEโ invalid character class type referenced.REG_EESCAPEโ trailing<backslash>character inpattern.REG_EPARENโ"\(\)"or"()"imbalance.REG_ERANGEโ invalid endpoint in range expression.REG_ESPACEโ out of memory. ๐REG_ESUBREGโ number in"\digit"invalid or in error.REG_NOMATCHโregexec()failed to match.
if more than one error occurs in processing a function call, any one of the possible constants may be returned, as the order of detection is unspecified. so like... don't count on a specific one, okay? ๐
๐ regerror() โ the translator ๐
regerror() provides a mapping from error codes returned by regcomp() and regexec() to unspecified printable strings. she generates a string corresponding to the value of the errcode argument โ and the application shall ensure that errcode is the last non-zero value returned by regcomp() or regexec() with the given value of preg.
if errcode is not such a value, the content of the generated string is unspecified. so be careful, bestie. ๐
If preg is a null pointer but errcode is a value that came back from an earlier regexec() or regcomp() call, regerror() will still cook up an error string for that errcode โ but lowkey, under some implementations it might not be as detailed as it could be. ๐คท
If errbuf_size is not 0, regerror() shall drop the generated string into the buffer of size errbuf_size bytes that errbuf points to. If the string โ including the terminating null โ can't fit in that buffer, regerror() shall truncate the string and null-terminate the result. No partial-null chaos, bestie, it always closes it off properly. โจ
If errbuf_size is 0, regerror() shall straight-up ignore the errbuf argument and just return the size of the buffer you'd need to hold the generated string. It's giving "just tell me how much room I need" energy. ๐
Okay so heads up: if thepregargument toregexec()orregfree()is not a compiled regular expression returned byregcomp(), the result is undefined. And apregis no longer treated as a compiled regular expression after it's been handed toregfree(). She's retired. Do not come back for her. ๐
โจ RETURN VALUE โจ
Upon successful completion, regcomp() shall return 0. Otherwise, it shall return an integer value indicating an error as described in <regex.h>, and the content of preg is undefined. If a code is returned, the interpretation shall be as given in <regex.h>. ๐
If regcomp() detects an invalid RE, it may return REG_BADPAT, or it may return one of the error codes that more precisely describes the error. Either way you're getting told. ๐ซถ
Upon successful completion, the regexec() function shall return 0. Otherwise, it shall return REG_NOMATCH to indicate no match. That's it, that's the whole "nope" signal.
Upon successful completion, the regerror() function shall return the number of bytes needed to hold the entire generated string, including the null termination. If the return value is greater than errbuf_size, the string returned in the buffer pointed to by errbuf has been truncated. ๐จ So if that number's bigger than what you gave it, bestie, you got a chopped string.
The regfree() function shall not return a value. It just does its thing and leaves. ๐
๐ธ ERRORS ๐ธ
No errors are defined.
The following sections are informative.
๐ EXAMPLES ๐
Okay this first one is the classic โ matching a string against an extended regular expression in pattern, and treating any error as a no-match. It returns 1 for a match, 0 for no match:
#include <regex.h>
/*
* Match string against the extended regular expression in
* pattern, treating errors as no match.
*
* Return 1 for match, 0 for no match.
*/
int
match(const char *string, char *pattern)
{
int status;
regex_t re;
if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB) != 0) {
return(0); /* Report error. */
}
status = regexec(&re, string, (size_t) 0, NULL, 0);
regfree(&re);
if (status != 0) {
return(0); /* Report error. */
}
return(1);
}
Next up: the glow-up demo of how you'd use the REG_NOTBOL flag with regexec() to find all the substrings in a line that match a pattern supplied by a user. (And fr, for simplicity of the example, very little error checking is done โ don't @ me.) ๐ฆ
(void) regcomp (&re, pattern, 0);
/* This call to regexec() finds the first match on the line. */
error = regexec (&re, &buffer[0], 1, &pm, 0);
while (error == 0) { /* While matches found. */
/* Substring found between pm.rm_so and pm.rm_eo. */
/* This call to regexec() finds the next match. */
error = regexec (&re, buffer + pm.rm_eo, 1, &pm, REG_NOTBOL);
}
๐ APPLICATION USAGE ๐
An application could use:
regerror(code,preg,(char *)NULL,(size_t)0)
to find out how big a buffer is needed for the generated string, then malloc() a buffer to hold the string, and then call regerror() again to actually get the string. Two-step, but it works. ๐ซ
Alternatively, it could allocate a fixed, static buffer that's big enough to hold most strings, and then use malloc() to allocate a larger buffer if it turns out that one was too small. Plan B energy, iconic.
And if you're trying to match a pattern as described in the Shell and Utilities volume of POSIX.1โ2017, Section 2.13, Pattern Matching Notation โ bestie, use the fnmatch() function. That's the one you want for that job. ๐ซถ
๐ญ RATIONALE ๐ญ
Okay so first thing, bestie: regexec() has to fill in all nmatch elements of pmatch โ and those two are supplied by the application. Even if some elements of pmatch do not correspond to subexpressions in pattern, they still get filled in. And app devs should lowkey know there's probably no reason to use an nmatch value bigger than preg->re_nsub+1. Periodt. ๐
The REG_NEWLINE flag supports a use of RE matching that's needed in some applications like text editors. In those apps, the user supplies an RE asking the application to find a line that matches the given expression. An anchor in such an RE anchors at the beginning or end of any line. Such an application can pass a sequence of <newline>-separated lines to regexec() as a single long string and specify REG_NEWLINE to regcomp() to get the desired behavior. The application must ensure that there are no explicit <newline> characters in pattern if it wants to ensure that any match occurs entirely within a single line. Slay, but stay careful. โจ
The REG_NEWLINE flag affects the behavior of regexec(), but it is in the cflags parameter to regcomp() to allow flexibility of implementation. Some implementations will want to generate the same compiled RE in regcomp() regardless of the setting of REG_NEWLINE and have regexec() handle anchors differently based on the setting of the flag. Other implementations will generate different compiled REs based on the REG_NEWLINE. Both are valid vibes, iykyk. ๐ฆ
The REG_ICASE flag supports the operations taken by the grep -i option and the historical implementations of ex and vi. Including this flag will make it easier for application code to be written that does the same thing as these utilities. Iconic behavior, honestly. ๐ธ
The substrings reported in pmatch[] are defined using offsets from the start of the string rather than pointers. This allows type-safe access to both constant and non-constant strings. Type safety? We love to see it. ๐
The type regoff_t is used for the elements of pmatch[] to ensure that the application can represent large arrays in memory โ important for an application conforming to the Shell and Utilities volume of POSIX.1โ2017. Big arrays, big main character energy. ๐
The 1992 edition of this standard required regoff_t to be at least as wide as off_t, to facilitate future extensions in which the string to be searched is taken from a file. However, these future extensions have not appeared. The requirement rules out popular implementations with 32-bit regoff_t and 64-bit off_t, so it has been removed. Not me reading the lore. ๐ญ
The standard developers rejected the inclusion of a regsub() function that would be used to do substitutions for a matched RE. While such a routine would be useful to some applications, its utility would be much more limited than the matching function described here. Both RE parsing and substitution are possible to implement without support other than that required by the ISO C standard, but matching is much more complex than substituting. The only difficult part of substitution, given the information supplied by regexec(), is finding the next character in a string when there can be multi-byte characters. That is a much larger issue, and one that needs a more general solution. So no regsub(), bestie. It's giving โwe thought about it and said no.โ ๐
The errno variable has not been used for error returns to avoid filling the errno name space for this feature. Respectful. Considerate. Keeping the namespace cute. ๐
The interface is defined so that the matched substrings rm_sp and rm_ep are in a separate regmatch_t structure instead of in regex_t. This allows a single compiled RE to be used simultaneously in several contexts; in main() and a signal handler, perhaps, or in multiple threads of lightweight processes. (The preg argument to regexec() is declared with type const, so the implementation is not permitted to use the structure to store intermediate results.) It also allows an application to request an arbitrary number of substrings from an RE. The number of subexpressions in the RE is reported in re_nsub in preg. With this change to regexec(), consideration was given to dropping the REG_NOSUB flag since the user can now specify this with a zero nmatch argument to regexec(). However, keeping REG_NOSUB allows an implementation to use a different (perhaps more efficient) algorithm if it knows in regcomp() that no subexpressions need be reported. The implementation is only required to fill in pmatch if nmatch is not zero and if REG_NOSUB is not specified. Note that the size_t type, as defined in the ISO C standard, is unsigned, so the description of regexec() does not need to address negative values of nmatch. That's a whole paragraph but every word is doing its job. ๐
REG_NOTBOL was added to allow an application to do repeated searches for the same pattern in a line. If the pattern contains a <circumflex> character that should match the beginning of a line, then the pattern should only match when matched against the beginning of the line. Without the REG_NOTBOL flag, the application could rewrite the expression for subsequent matches, but in the general case this would require parsing the expression. The need for REG_NOTEOL is not as clear; it was added for symmetry. Symmetry, the aesthetic. โจ
The addition of the regerror() function addresses the historical need for conforming application programs to have access to error information more than ``Function failed to compile/match your RE for unknown reasons''. That old message was giving absolutely nothing. ๐ญ
This interface provides for two different methods of dealing with error conditions. The specific error codes (REG_EBRACE, for example), defined in <regex.h>, allow an application to recover from an error if it is so able. Many applications, especially those that use patterns supplied by a user, will not try to deal with specific error cases, but will just use regerror() to obtain a human-readable error message to present to the user. Two paths, both valid, no judgment. ๐ซถ
The regerror() function uses a scheme similar to confstr() to deal with the problem of allocating memory to hold the generated string. The scheme used by strerror() in the ISO C standard was considered unacceptable since it creates difficulties for multi-threaded applications. Threads said โnot today,โ and honestly same. ๐ง
The preg argument is provided to regerror() to allow an implementation to generate a more descriptive message than would be possible with errcode alone. An implementation might, for example, save the character offset of the offending character of the pattern in a field of preg, and then include that in the generated message string. The implementation may also ignore preg. Flexible. Chill. Whatever works. ๐
A REG_FILENAME flag was considered, but omitted. This flag caused regexec() to match patterns as described in the Shell and Utilities volume of POSIX.1โ2017, Section 2.13, Pattern Matching Notation instead of REs. This service is now provided by the fnmatch() function. She left, but her legacy lives on in fnmatch(). ๐ฆ
Notice that there is a difference in philosophy between the ISO POSIXโ2:1993 standard and POSIX.1โ2008 in how to handle a bad'' regular expression.</pink> The ISO POSIXโ2:1993 standard says that many bad constructs produce undefined results'', or that the interpretation is undefined''. POSIX.1โ2008, however, says that the interpretation of such REs is unspecified. <rainbow>The term undefined'' means that the action by the application is an error, of similar severity to passing a bad pointer to a function. So likeโฆ do not play with that. Seriously. ๐
The regcomp() and regexec() functions are required to accept any null-terminated string as the pattern argument. If the meaning of the string is undefined'', the behavior of the function is unspecified''. POSIX.1โ2008 does not specify how the functions will interpret the pattern; they might return error codes, or they might do pattern matching in some completely unexpected way, but they should not do something like abort the process. So: chaotic maybe, but not murder. Good to know. ๐ญ
๐ฎ FUTURE DIRECTIONS ๐ฎ
None. Like, genuinely none. The future is a blank canvas and this page is not adding anything to it. Iconic minimalism. ๐
๐ SEE ALSO ๐
fnmatch(),glob()- The Base Definitions volume of POSIX.1โ2017, Chapter 9, Regular Expressions,
<regex.h>,<sys_types.h> - The Shell and Utilities volume of POSIX.1โ2017, Section 2.13, Pattern Matching Notation
๐ COPYRIGHT ๐
Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1-2017, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 7, 2018 Edition, Copyright (C) 2018 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .
Any typographical or formatting errors that appear in this page are most likely to have been introduced during the conversion of the source files to man page format. To report such errors, see https://www.kernel.org/doc/man-pages/reporting_bugs.html .
๐ That's the whole vibe, bestie. This page is REGCOMP(3POSIX), source/version IEEE/The Open Group, date 2017. Stay matching, stay safe, and never abort the process. ๐
โจ
๐ฆ where this page comes from
- debian bookworm: manpages-posix-dev 2017a-2 ยท Other
- debian trixie: manpages-posix-dev 2017a-2 ยท Other
- ubuntu jammy: manpages-posix-dev 2017a-2 ยท Other
- ubuntu noble: manpages-posix-dev 2017a-2 ยท Other
- ubuntu resolute: manpages-posix-dev 2017a-2build1 ยท Other
- ubuntu stonking: manpages-posix-dev 2017a-2.1 ยท Other
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms