目录
[2.1.字符串查找(Find)](#2.1.字符串查找(Find))
[2.2.正则匹配(REGEX MATCH)](#2.2.正则匹配(REGEX MATCH))
[2.4.正则匹配替换(REGEX REPLACE)](#2.4.正则匹配替换(REGEX REPLACE))
1.简介
string
命令是 CMake 中处理文本的核心工具,支持字符串的查找、替换、转换、分割、生成等操作。其功能类似编程语言中的字符串库,可用于构建路径处理、版本号解析、代码生成等场景。string 指令的基本语法如下:
cpp
string(<command> ...)
<command> : 是您希望执行的操作类型,比如 LENGTH,APPEND,REPLACE 等。
LENGTH:计算字符串的长度。
APPEND:将一个字符串附加到另一个字符串后面。
REPLACE:替换字符串中的一部分内容。
SUBSTRING:提取字符串的子字符串。
COMPARE:比较两个字符串大小,是否相等。
TOUPPER/TOLOWER:将字符串转换为大写/小写。
REGEX REPLACE:字符串查找和替换,使用正则表达式匹配和替换字符串的某些部分。
CONCAT:字符串连接。
FIND:用于在字符串中查找一个子字符串位置。
REGEX MATCH:用于在字符串中查找正则表达式匹配的内容。
。。。
...: 后面的形参根据不同的指令各有差异,下面我们会根据command类型一一示例进行介绍。
2.常用命令介绍
2.1.字符串查找(Find)
查找子串在字符串中的位置(索引从 0 开始,未找到返回 -1
):
cpp
string(FIND <string> <substring> <output_variable> [REVERSE])
在 <string> 中查找 <substring> 的位置,位置基础是从0开始,结果是<substring> 开始的索引,存储在 <output_variable> 中,如果没找到,输出 -1。可选的[REVERSE]参数表示从字符串的末尾开始向前搜索。使用REVERSE选项对于查找最后一次出现的位置特别有用,尤其是在处理包含多个相同子字符串的长字符串时。这提供了一种灵活的方式来从不同的方向分析和处理字符串数据。
示例如下:
cpp
string(FIND "hello world" "world" pos) # pos = 6
string(FIND "hello world" "x" pos) # pos = -1
2.2.正则匹配(REGEX MATCH)
cpp
string(REGEX MATCH <regex> <output variable> <input> [<input>...])
这个模式用于在输入字符串中查找与正则表达式匹配的部分。如果找到匹配的部分,它将被存储在输出变量中。
示例如下:
cpp
#匹配数字
string(REGEX MATCH "[0-9]+" "version 1.2.3" version_num) # version_num = 1
# 设置包含数字的文本字符串
set(input_text "The 2 quick brown foxes jump over 13 lazy dogs 8 times.")
# 使用正则表达式匹配所有数字
string(REGEX MATCHALL "[0-9]+" matched_numbers ${input_text})
# 打印匹配到的所有数字
message("Matched numbers are: ${matched_numbers}")
2.3.字符串替换(REPLACE)
替换字符串中的子串(非正则匹配):
cpp
string(REPLACE <match> <replace> <output_variable> <string>)
在<string>
字符串中搜索 <match>
并将其替换为<replace>
,结果存储在 <output_variable>
中。
示例如下:
cpp
string(REPLACE "world" "CMake" "hello world" result) # result = "hello CMake"
2.4.正则匹配替换(REGEX REPLACE
)
使用正则表达式替换匹配的部分:
cpp
string(REGEX REPLACE <regex> <replace> <output_variable> <string>)
对 <string>
使用正则表达式 <regex>
进行查找,并用<replace>
进行替换,结果存储在 <output_variable>
中。
示例如下:
cpp
string(REGEX REPLACE "([0-9]+)\\.([0-9]+)" "v\\1_\\2" "1.2" version) # version = "v1_2"
2.5.截取子串(SUBSTRING
)
截取字符串的子串:
cpp
string(SUBSTRING <string> <begin> <length> <output_variable>)
提取 <string>
的子字符串,从 <begin>
开始,长度为 <length>
,结果存储在 <output_variable>
中。
示例如下:
cpp
#1
string(SUBSTRING "hello" 1 3 result) # result = "ell" (索引 1 开始,长度 3)
#2
set(MY_STR "Hello, world!")
string(SUBSTRING "${MY_STR}" 0 5 SUB_STR)
message(STATUS "子字符串: ${SUB_STR}") # 输出应为 "Hello"
2.6.大小写转换(TOUPPER
/TOLOWER
)
转换字符串大小写:
cpp
string(TOUPPER <string> <output_variable>)
string(TOLOWER <string> <output_variable>)
示例如下:
cpp
string(TOUPPER "hello" upper) # upper = "HELLO"
2.7.去除字符串首尾的空格或指定字符(STRIP
)
去除字符串首尾的空格或指定字符:
cpp
string(STRIP <string> <output_variable>)
示例如下:
cpp
string(STRIP " hello " result) # result = "hello"
2.8.字符串分割(SPLIT
)
按分隔符将字符串拆分为列表(类似 Python 的 split()
):
cpp
string(SPLIT <string> <delimiter> <output_variable>)
示例如下:
cpp
string(SPLIT "a;b;c" ";" list_var) # list_var = ["a", "b", "c"]
2.9.字符串连接(JOIN
)
用分隔符连接列表为字符串(类似 Python 的 join()
):
cpp
string(JOIN <delimiter> <output_variable> <input1> <input2> ...)
示例如下:
cpp
string(JOIN "," output "a" "b" "c") # output = "a,b,c"
2.10.字符串长度(LENGTH
)
获取字符串长度:
cpp
string(LENGTH <string> <output_variable>)
示例如下:
cpp
string(LENGTH "hello" len) # len = 5
2.11.字符串比较(COMPARE
)
字符串比较有两种方法。
1.通过条件语句使用 STREQUAL
,STRLESS
和 STRGREATER
来比较字符串
STREQUAL:字符串相等比较。如果相等,则表达式结果为 TRUE,否则为 FALSE。
STRLESS:用于判断一个字符串是否在字典排序上小于另一个字符串。如果是,则表达式结果为 TRUE,否则为 FALSE。
STRGREATER:用于判断一个字符串是否在字典排序上大于另一个字符串。如果是,则表达式结果为 TRUE,否则为 FALSE。
示例如下:
cpp
set(var1 "Hello")
set(var2 "World")
if("${var1}" STRLESS "${var2}")
message(STATUS "var1 is less than var2.")
else()
message(STATUS "var1 is not less than var2.")
endif()
if("${var1}" STRGREATER "${var2}")
message(STATUS "var1 is greater than var2.")
else()
message(STATUS "var1 is not greater than var2")
endif()
if("${var1}" STREQUAL "${var2}")
message(STATUS "var1 is equal to var2.")
else()
message(STATUS "var1 is not equal to var2.")
endif()
2.另一种比较字符串的方法
cpp
string(COMPARE <op> <string1> <string2> <output variable>)
这里的<op>
是比较操作符,<op>
是EQUAL
、LESS
、GREATER
,比较结果的返回值同上面STREQUAL
、STRLESS
、STRGREATER
。<string1>
和<string2>
是要比较的字符串,而<output variable>
是用来存储比较结果的变量。
cpp
set(var1 "Hello")
set(var2 "World")
string(COMPARE EQUAL "${var1}" "${var2}" result)
if(result)
message(STATUS "The strings are equal")
else()
message(STATUS "The strings are not equal")
endif()
string(COMPARE LESS "${var1}" "${var2}" result)
if(result)
message(STATUS "var1 is less than var2")
else()
message(STATUS "var1 is not less than var2")
endif()
string(COMPARE GREATER "${var1}" "${var2}" result)
if(result)
message(STATUS "var1 is greater than var2")
else()
message(STATUS "var1 is not greater than var2")
2.13.字符串串联(CONCAT)
cpp
string(CONCAT <output_variable> <input> ...)
将所有 <input>
字符串拼接起来,结果存储在 <output_variable>
中
示例如下:
cpp
set(STR1 "Hello, ")
set(STR2 "World!")
string(CONCAT CONNECTED_STR ${STR1} ${STR2})
message(STATUS "Connected string: ${CONNECTED_STR}")
2.14.字符串附加(APPEND)
cpp
string(APPEND <variable> <string> [<string>...])
将一个或多个 <string>
附加到变量 <variable>
的值上。
示例如下:
cpp
# 初始为空的编译标志
set(COMPILER_FLAGS "")
# 根据需要附加标志
string(APPEND COMPILER_FLAGS "-Wall ")
string(APPEND COMPILER_FLAGS "-Werror ")
string(APPEND COMPILER_FLAGS "-O3")
# 打印最终的编译标志
message(STATUS "Compiler flags: ${COMPILER_FLAGS}")
注意事项:
1.在指定多个值进行追加时,string(APPEND ...)不会在这些值之间自动添加任何分隔符。如果需要分隔符(如空格或其他字符),你必须自己包括它们在值中。
2.和大部分CMake命令一样,string(APPEND ...)修改变量的作用是在原地执行的,意味着它直接改变了传入的变量而不是返回一个新的修改后的副本。
2.15.根据模板生成字符串(GENERATE
)
根据模板生成字符串(常用于生成配置文件):
cpp
string(GENERATE <output_file> <content> [ESCAPE_QUOTES])
示例如下:
cpp
string(GENERATE "config.h" "#define VERSION \"${PROJECT_VERSION}\"")
2.16.计算字符串的哈希值(HASH)
计算字符串的哈希值(支持 MD5/SHA1/SHA256 等):
cpp
string(HASH <algorithm> <output_variable> <string>)
示例如下:
cpp
string(HASH SHA256 hash "hello") # hash = "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9"
3.字符串连接CONCAT和字符串附加APPEND的区别
1.string(CONCAT ...)
:创建新字符串
将多个字符串参数连接成一个新字符串,并存储到指定变量中。原字符串不会被修改。
cpp
string(CONCAT full_name "John" " " "Doe") # full_name = "John Doe"
# 结合变量使用
set(PREFIX "lib")
set(NAME "mylib")
set(EXT ".a")
string(CONCAT LIB_FILE ${PREFIX} ${NAME} ${EXT}) # LIB_FILE = "libmylib.a"
2.string(APPEND ...)
:追加到已有字符串
将一个或多个字符串追加到已有变量的末尾,直接修改原变量的值。若变量不存在,则创建并初始化。
cpp
set(message "Hello")
string(APPEND message " World!") # message 变为 "Hello World!"
# 多次追加
string(APPEND message " Have a nice day.") # message 变为 "Hello World! Have a nice day."
3.核心区别对比
特性 | string(CONCAT ...) |
string(APPEND ...) |
---|---|---|
是否创建新变量 | 必须指定新变量存储结果 | 直接修改已有变量(若不存在则创建) |
原字符串是否修改 | 否 | 是 |
典型场景 | 一次性拼接多个字符串 | 逐步构建字符串(如循环追加) |
示例 | string(CONCAT out "a" "b" "c") |
string(APPEND var "a";"b";"c") |
4.使用场景对比
CONCAT
适用场景:
- 构建路径或文件名(如
bin/${PROJECT_NAME}
)。 - 生成版本号字符串(如
v${VERSION_MAJOR}.${VERSION_MINOR}
)。 - 一次性拼接多个固定字符串。
APPEND
适用场景:
- 逐步构建编译选项(如
string(APPEND CMAKE_CXX_FLAGS " -Wall -Werror")
)。 - 循环追加内容(如收集所有源文件路径):
cpp
set(SOURCES "")
foreach(file IN LISTS file_list)
string(APPEND SOURCES "${file};") # 追加并以分号分隔
endforeach()
- 动态生成配置文件内容:
cpp
string(APPEND config_content "#define VERSION ${PROJECT_VERSION}\n")
string(APPEND config_content "#define DEBUG ${DEBUG_MODE}\n")
4.典型应用场景
1.版本号解析:
cpp
set(VERSION "1.2.3")
string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" _ ${VERSION})
set(VERSION_MAJOR ${CMAKE_MATCH_1}) # 1
set(VERSION_MINOR ${CMAKE_MATCH_2}) # 2
set(VERSION_PATCH ${CMAKE_MATCH_3}) # 3
2.路径处理:
cpp
set(PATH "/usr/local/bin")
string(REPLACE "/" ";" PATH_LIST ${PATH}) # PATH_LIST = ["usr", "local", "bin"]
3.条件编译配置:
cpp
if(DEBUG)
string(APPEND CMAKE_CXX_FLAGS " -DDEBUG=1")
endif()
5.注意事项
1.正则表达式语法
- CMake 的正则语法类似 Perl,但需注意转义(如
\\
表示反斜杠)。 - 常用元字符:
^
(开头)、$
(结尾)、[0-9]
(数字)、.*
(任意字符)。
2.字符串与列表转换
- CMake 列表本质是分号分隔的字符串,可通过
string(SPLIT)
和string(JOIN)
相互转换。
3.变量作用域
- 字符串操作结果需存入变量,不会直接修改原字符串(除非覆盖同名变量)。
通过灵活使用 string
命令,可高效处理 CMake 中的文本逻辑,避免复杂的外部脚本依赖。
相关链接
- CMake 官网 CMake - Upgrade Your Software Build System
- CMake 官方文档:CMake Tutorial --- CMake 4.0.2 Documentation
- CMake 源码:GitHub - Kitware/CMake: Mirror of CMake upstream repository
- CMake 源码:Sign in · GitLab