1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-14 02:08:27 +08:00

string: Add REGEX QUOTE sub-command

Add a command to generate a regular expression that matches an
input string literally by escaping special characters.

Fixes: #18580
This commit is contained in:
Timo Röhling
2025-09-17 22:26:55 +02:00
committed by Brad King
parent a3ccb05430
commit d94d79a909
4 changed files with 61 additions and 0 deletions

View File

@@ -27,6 +27,7 @@ Synopsis
string(`STRIP`_ <string> <out-var>)
string(`GENEX_STRIP`_ <string> <out-var>)
string(`REPEAT`_ <string> <count> <out-var>)
string(`REGEX QUOTE`_ <out-var> <input>...)
`Comparison`_
string(`COMPARE`_ <op> <string1> <string2> <out-var>)
@@ -290,6 +291,16 @@ Manipulation
Produce the output string as the input ``<string>``
repeated ``<count>`` times.
.. signature::
string(REGEX QUOTE <out-var> <input>...)
.. versionadded:: 4.2
Store in an ``<out-var>`` a regular expression matching the ``<input>``.
All characters that have special meaning in a regular expressions are
escaped, such that the output string can be used as part of a regular
expression to match the input literally.
Comparison
^^^^^^^^^^

View File

@@ -0,0 +1,5 @@
string-regex-quote
------------------
* The :command:`string(REGEX QUOTE)` command was added to
generate a regular expression exactly matching a string.

View File

@@ -47,6 +47,8 @@ bool RegexMatchAll(std::vector<std::string> const& args,
cmExecutionStatus& status);
bool RegexReplace(std::vector<std::string> const& args,
cmExecutionStatus& status);
bool RegexQuote(std::vector<std::string> const& args,
cmExecutionStatus& status);
bool joinImpl(std::vector<std::string> const& args, std::string const& glue,
size_t varIdx, cmMakefile& makefile);
@@ -218,6 +220,14 @@ bool HandleRegexCommand(std::vector<std::string> const& args,
}
return RegexReplace(args, status);
}
if (mode == "QUOTE") {
if (args.size() < 4) {
status.SetError("sub-command REGEX, mode QUOTE needs "
"at least 4 arguments total to command.");
return false;
}
return RegexQuote(args, status);
}
std::string e = "sub-command REGEX does not recognize mode " + mode;
status.SetError(e);
@@ -356,6 +366,28 @@ bool RegexReplace(std::vector<std::string> const& args,
return true;
}
bool RegexQuote(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
//"STRING(REGEX QUOTE <output variable> <input> [<input>...]\n"
std::string const& outvar = args[2];
std::string const input =
cmJoin(cmMakeRange(args).advance(3), std::string());
std::string output;
// Escape all regex special characters
cmStringReplaceHelper replaceHelper("([][()+*^.$?|\\\\])", R"(\\\1)");
if (!replaceHelper.Replace(input, output)) {
status.SetError(
"sub-command REGEX, mode QUOTE: " + replaceHelper.GetError() + ".");
return false;
}
// Store the output in the provided variable.
status.GetMakefile().AddDefinition(outvar, output);
return true;
}
bool HandleFindCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{

View File

@@ -115,6 +115,19 @@ if(NOT "${CMAKE_MATCH_2}" STREQUAL "")
message(SEND_ERROR "CMAKE_MATCH_2 wrong: \"${CMAKE_MATCH_2}\", expected empty string")
endif()
set(regex_quote "ab|c+12?3[x-z]$(y)\\t\\r\\n.cma*ke^[:alpha:]")
string(REGEX QUOTE regex_quote_output "${regex_quote}")
if(NOT regex_quote MATCHES "^${regex_quote_output}$")
message(SEND_ERROR "string(REGEX QUOTE) problem: \"${regex_quote}\" does not match against \"^${regex_quote_output}$\"")
endif()
string(REPLACE "." "a" nomatch_regex_quote "${regex_quote}")
if(nomatch_regex_quote MATCHES "^${regex_quote_output}$")
message(SEND_ERROR "string(REGEX QUOTE) problem: \"${nomatch_regex_quote}\" matches against \"^${regex_quote_output}$\"")
endif()
string(REGEX QUOTE multi_regex_quote ${regex_quote} ${regex_quote})
if(NOT "${regex_quote}${regex_quote}" MATCHES "^${multi_regex_quote}$")
message(SEND_ERROR "string(REGEX QUOTE) problem: \"${regex_quote}${regex_quote}\" does not match against \"^${multi_regex_quote}$\"")
endif()
string(STRIP "
ST1