CMake中的string命令用于字符串操作,其格式如下:

Search and Replace
  string(FIND <string> <substring> <out-var> [...])
  string(REPLACE <match-string> <replace-string> <out-var> <input>...)
  string(REGEX MATCH <match-regex> <out-var> <input>...)
  string(REGEX MATCHALL <match-regex> <out-var> <input>...)
  string(REGEX REPLACE <match-regex> <replace-expr> <out-var> <input>...)

Manipulation
  string(APPEND <string-var> [<input>...])
  string(PREPEND <string-var> [<input>...])
  string(CONCAT <out-var> [<input>...])
  string(JOIN <glue> <out-var> [<input>...])
  string(TOLOWER <string> <out-var>)
  string(TOUPPER <string> <out-var>)
  string(LENGTH <string> <out-var>)
  string(SUBSTRING <string> <begin> <length> <out-var>)
  string(STRIP <string> <out-var>)
  string(GENEX_STRIP <string> <out-var>)
  string(REPEAT <string> <count> <out-var>)

Comparison
  string(COMPARE <op> <string1> <string2> <out-var>)

Hashing
  string(<HASH> <out-var> <input>)

Generation
  string(ASCII <number>... <out-var>)
  string(HEX <string> <out-var>)
  string(CONFIGURE <string> <out-var> [...])
  string(MAKE_C_IDENTIFIER <string> <out-var>)
  string(RANDOM [<option>...] <out-var>)
  string(TIMESTAMP <out-var> [<format string>] [UTC])
  string(UUID <out-var> ...)

JSON
  string(JSON <out-var> [ERROR_VARIABLE <error-var>]
         {GET | TYPE | LENGTH | REMOVE}
         <json-string> <member|index> [<member|index> ...])
  string(JSON <out-var> [ERROR_VARIABLE <error-var>]
         MEMBER <json-string>
         [<member|index> ...] <index>)
  string(JSON <out-var> [ERROR_VARIABLE <error-var>]
         SET <json-string>
         <member|index> [<member|index> ...] <value>)
  string(JSON <out-var> [ERROR_VARIABLE <error-var>]
         EQUAL <json-string1> <json-string2>)

      1.Search and Replace:
      (1).FIND:在提供的<string>中查找给定的<substring>,若找到则返回其位置;如果使用了REVERSE标志,该命令将搜索<substring>在<string>中最后出现的位置;若未找到则返回-1。string(FIND)子命令将所有字符串视为纯ASCII字符。变量<out-var>中存储的索引也会以字节为单位计算,因此包含多字节字符的字符串(strings containing multi-byte characters)可能会导致意外结果(unexpected results)。

set(str beijing//beijing//beijing)

string(FIND ${str} "jing" var)
message("var: ${var}") # var: 3
string(FIND ${str} "jing" var REVERSE)
message("var: ${var}") # var: 21
string(FIND ${str} "\\" var)
message("var: ${var}") # var: -1

      (2).REPLACE:将<input>中所有出现的<match_string>替换为<replace_string>,并将结果存储在<out-var>中。若<match_string>在<input>中未出现,<out-var>的值将为<input>。

set(str https://blog.csdn.net/fengbingchun)
string(REPLACE "blog.csdn.net" "github.com" var ${str})
message("var: ${var}") # var: https://github.com/fengbingchun

string(REPLACE "xxxx" "yyyy" var ${str}) 
message("var: ${var}") # var: https://blog.csdn.net/fengbingchun

      (3).CMake中的正则表达式(Regular Expression):以下字符在正则表达式中具有特殊含义
      ^:匹配输入字符串的开始位置;
      $:匹配输入字符串结尾的位置;
      .:匹配任何单个字符;
      \<char>:匹配<char>指定的单个字符。使用它来匹配特殊的正则表达式字符。将下一个字符标记为特殊字符。转义非特殊字符(non-special character)是不必要但允许的,例如\a匹配a;
      []:匹配括号内的任何字符;
      [^]:匹配不在括号内的任何字符;
      -:在括号内,指定两边字符之间的包含范围;
      *:零次或多次匹配前面的字符;
      +:一次或多次匹配前面的字符;
      ?:零次或一次匹配前面的字符;
      |:匹配"|"两边的字符;
      ():保存匹配的子表达式;
      *、+和?具有比串联(concatenation)更高的优先级。|的优先级低于concatenation。这意味着正则表达式^ab+d$匹配abbd但不匹配ababd,正则表达式^(ab|cd)$匹配ab但不匹配abd。
      CMake语言转义序列(Escape Sequences),例如\t、\r、\n和\\可用于构造文字制表符、回车符、换行符和反斜杠(literal tabs, carriage returns, newlines, and backslashes)以传入正则表达式。例如:
      带引号的参数"[ \t\r\n]"指定匹配任何单个空白字符的正则表达式;
      带引号的参数"[/\\]"指定匹配单个正斜杠/或反斜杠\的正则表达式;
      带引号的参数"[A-Za-z0-9_]"指定匹配C语言环境中任何单个"word"字符的正则表达式;
      带引号的参数"\\(\\a\\+b\\)"指定匹配确切字符串(a+b)的正则表达式。每个\\在带引号的参数中被解析为只是\,因此正则表达式本身实际上是\(\a\+\b\)。这也可以在括号参数中指定,而不必转义反斜杠,例如[[\(\a\+\b\)]]。
      REGEX MATCH:匹配一次<match-regex>并将匹配存储在<out-var>中。所有<input>参数在匹配之前连接(concatenated)。

set(str "123abc123abc")
string(REGEX MATCH "[a-z]" var ${str})
message("var: ${var}") # var: a
string(REGEX MATCH "[1-9]" var ${str})
message("var: ${var}") # var: 1
string(REGEX MATCH "[^1-9]" var ${str})
message("var: ${var}") # var: a

      REGEX MATCHALL:尽可能多地匹配<match-regex>并将匹配项作为列表(list)存储在<out-var>中。所有<input>参数在匹配之前连接(concatenated)。

set(str "123abc123abc")
string(REGEX MATCHALL "[a-z]" var ${str})
message("var: ${var}") # var: a;b;c;a;b;c
string(REGEX MATCHALL "[1-9]" var ${str})
message("var: ${var}") # var: 1;2;3;1;2;3
string(REGEX MATCHALL "[^1-9]" var ${str})
message("var: ${var}") # var: a;b;c;a;b;c

      REGEX REPLACE:尽可能多地匹配<match-regex>并将<replace-expr>替换为输出中的匹配项。所有<input>参数在匹配之前连接(concatenated)。

set(str "123abc123abc")
set(substr "@#")

string(REGEX REPLACE "[a-z]" ${substr} var ${str})
message("var: ${var}") # var: 123@#@#@#123@#@#@#
string(REGEX REPLACE "[1-9]" ${substr} var ${str})
message("var: ${var}") # var: @#@#@#abc@#@#@#abc
string(REGEX REPLACE "[^1-9]" ${substr} var ${str})
message("var: ${var}") # var: 123@#@#@#123@#@#@#
string(REGEX REPLACE "^a" ${substr} var ${str}) # 若没有找到可replace的,则var=str
message("var: ${var}") # var: 123abc123abc

      2.Manipulation:
      (1).APPEND:将所有<input>参数追加到<string-var>

set(str1 "csdn addr:")
string(APPEND var ${str1})

set(str2 "https://blog.csdn.net/fengbingchun")
string(APPEND var ${str2})
message("var: ${var}") # var: csdn addr:https://blog.csdn.net/fengbingchun

      (2).PREPEND:将所有<input>参数前置(prepend)到<string-var>

set(str1 "https://blog.csdn.net/fengbingchun")
string(PREPEND var ${str1})

set(str2 "csdn addr:")
string(PREPEND var ${str2})
message("var: ${var}") # var: csdn addr:https://blog.csdn.net/fengbingchun

      (3).CONCAT:将所有<input>参数连接在一起,并将结果存储在<out-var>中

set(str1 "csdn addr:")
set(str2 "https://blog.csdn.net/fengbingchun")
string(CONCAT var ${str1} ${str2})
message("var: ${var}") # var: csdn addr:https://blog.csdn.net/fengbingchun

      (4).JOIN:使用<glue>字符串将所有<input>参数连接在一起,并将结果存储在<out-var>中

set(str1 "csdn addr")
set(str2 "https://blog.csdn.net/fengbingchun")
string(JOIN ": " var ${str1} ${str2})
message("var: ${var}") # var: csdn addr: https://blog.csdn.net/fengbingchun

      (5).TOLOWER:将<string>转换为小写字符

set(str "ABC123dEF")
string(TOLOWER ${str} var)
message("var: ${var}") # var: abc123def

      (6).TOUPPER:将<string>转换为大写字符

set(str "AbC123dEf")
string(TOUPPER ${str} var)
message("var: ${var}") # var: ABC123DEF

      (7).LENGTH:将给定<string>的长度(以字节为单位)存储在<out-var>中。注意:这意味着如果<string>包含多字节字符,则存储在<out-var>中的结果将不是字符数

set(str "https://blog.csdn.net/fengbingchun")
string(LENGTH ${str} var)
message("var: ${var}") # var: 34

      (8).SUBSTRING:在<out-var>中存储给定<string>的子字符串。如果<length>为-1,则将返回从<begin>开始的字符串的其余部分。如果<string>比<length>短,则使用字符串的结尾。<begin>和<length>都以字节为单位,因此如果<string>包含多字节字符,则必须小心

set(str "https://blog.csdn.net/fengbingchun")

string(SUBSTRING ${str} 8 13 var)
message("var: ${var}") # var: blog.csdn.net

string(SUBSTRING ${str} 8 100 var)
message("var: ${var}") # var: blog.csdn.net/fengbingchun

string(SUBSTRING ${str} 8 -1 var)
message("var: ${var}") # var: blog.csdn.net/fengbingchun

      (9).STRIP:将除去前后空格(leading and trailing spaces removed)的<string>的子字符串存储在<out-var>中

set(str "  https://blog.csdn.net/fengbingchun  ")
string(STRIP ${str} var)
message("str: ${str}") # str:   https://blog.csdn.net/fengbingchun  
message("var: ${var}") # var: https://blog.csdn.net/fengbingchun

      (10).GENEX_STRIP:从输入<string>中去除"generator expressions"并将结果存储在<out-var>中

set(str "one;$<1:two;three>;four;$<TARGET_OBJECTS:some_target>")
string(GENEX_STRIP "${str}" var) # string(GENEX_STRIP "one;$<1:two;three>;four;$<TARGET_OBJECTS:some_target>" var)
message("var: ${var}") # var: one;four

      (11).REPEAT:输出字符串作为输入<string>重复<count>次

set(str "abcd1234")
string(REPEAT ${str} 3 var)
message("var: ${var}") # var: abcd1234abcd1234abcd1234

      3.Comparison:比较字符串并将true或false存储在<out-var>中,op有LESS、GREATER、EQUAL、NOTEQUAL、LESS_EQUAL、GREATER_EQUAL

set(str1 "abc")
set(str2 "acd")

string(COMPARE LESS ${str1} ${str2} var)
message("var: ${var}") # var: 1
string(COMPARE GREATER ${str1} ${str2} var)
message("var: ${var}") # var: 0

string(COMPARE EQUAL ${str1} ${str1} var)
message("var: ${var}") # var: 1
string(COMPARE NOTEQUAL ${str1} ${str1} var)
message("var: ${var}") # var: 0

string(COMPARE LESS_EQUAL ${str1} ${str1} var)
message("var: ${var}") # var: 1
string(COMPARE GREATER_EQUAL ${str1} ${str1} var)
message("var: ${var}") # var: 1

      4.Hashing:计算<input>字符串的加密哈希(cryptographic hash)。支持的<HASH>算法包括:MD5、SHA1、SHA224、SHA256、SHA384、SHA512、SHA3_224、SHA3_256、SHA3_384、SHA3_512

set(str "https://blog.csdn.net/fengbingchun")
string(MD5 var ${str})
message("var: ${var}") # var: 347626e4d6ac64d0d193e4f7c9a527b1
string(SHA1 var ${str})
message("var: ${var}") # var: d0e47459e1e8115c11f5640e2595c7d35dfa5d4f
string(SHA224 var ${str})
message("var: ${var}") # var: e31ec2e82107a7acee703ea0ef08ea98d68aabad41725e80faf5795e
string(SHA256 var ${str})
message("var: ${var}") # var: 0220d436e044b408464a2d59a06a1af98ced88b17b4dffe7bdfd22420a2703ef
string(SHA384 var ${str})
message("var: ${var}") # var: 510f2226e793a2ef50aff6a7da133489b0f588b67e090f7a131d7f6d098855e22a917867222d0eea53d225689751dda4
string(SHA512 var ${str})
message("var: ${var}") # var: e301205b475e6288b8844d147cf28083f1dc847ea78c332a93061ccc950625acab5e857b76dbf95b5990ee387d935e7b5206f78a05be403bac83b1c0110acbcc
string(SHA3_224 var ${str})
message("var: ${var}") # var: 62f51871f691fb594f70f5e353f98e310f98c0e7f1030ed49e01747e
string(SHA3_256 var ${str})
message("var: ${var}") # var: 442a3127fd33cf6b89427b819dfb69c64f7805214fd1ff4c77bd33e85deebd99
string(SHA3_384 var ${str})
message("var: ${var}") # var: af8c8e24e984eee9874336401d3140b971074dcf94be3b7955350a8845143c09d318773e6d34da7347295af52308eec6
string(SHA3_512 var ${str})
message("var: ${var}") # var: ef3c281c1745c06c113f3e8d92acdc006a1f665f7fbc48b58f6fb871cb31bdb3f28e81c7f6e268b75d5861cf160720072f475f94f75335d7492ca14e1f0963a7

      5.Generation:
      (1).ASCII:将所有数字转换为对应的ASCII字符

set(num 33)
string(ASCII ${num} var)
message("var: ${var}") # var: !

string(ASCII 33 34 var)
message("var: ${var}") # var: !"

string(ASCII 256 var) # CMake Error at test_string.cmake:159 (string):
                        #   string Character with code 256 does not exist.

      (2).HEX:将输入的<string>中的每个字节转换为十六进制表示,并将连接后的十六进制数字存储在<out-var>中。输出中的字母(a到f)是小写的

set(str "!#$<=>Zz")
string(HEX ${str} var)
message("var: ${var}") # var: 2123243c3d3e5a7a 

      (3).CONFIGURE:像configure_file命令一样的规则转换<string>

set(csdn_addr "https://blog.csdn.net/fengbingchun")
string(CONFIGURE "#cmakedefine csdn_addr @csdn_addr@" var)
message("var: ${var}") # var: #define csdn_addr https://blog.csdn.net/fengbingchun

      (4).MAKE_C_IDENTIFIER:将<string>中的每个非字母数字字符(each non-alphanumeric character)转换为下划线并将结果存储在<out-var>中。如果<string>的第一个字符是数字,则下划线也将被添加到结果前

set(str "123^$abc*()ABC")
string(MAKE_C_IDENTIFIER ${str} var)
message("var: ${var}") # var: _123__abc___ABC

      (5).RANDOM:返回由<alphabet>中的字符组成的长度为<length>的随机字符串。默认长度为5个字符,默认字母为所有数字和大小写字母。如果给定一个整数<seed>,它的值将用于为随机数生成器提供种子(seed)

string(RANDOM [LENGTH <length>] [ALPHABET <alphabet>] [RANDOM_SEED <seed>] <output_variable>)
string(RANDOM LENGTH 20 ALPHABET abc123ABC RANDOM_SEED 5 var)
message("var: ${var}") # var: caCabac22CacCb1c1c1c

      (6).TIMESTAMP:将当前日期/或时间的字符串表示形式写入<out-var>。如果命令无法获取时间戳,<out-var>将设置为空字符串。
      可选的UTC标志请求当前日期/时间表示为协调世界时(UTC)而不是本地时间。
      可选的<format string>可能包含以下格式说明符:%%、%d、%H、%I、%j、%m、%b、%B、%M、%s、%S、%f、%U、%w、%a、%A、%y、%Y

string(TIMESTAMP var) # %Y-%m-%dT%H:%M:%S for local time
message("var: ${var}") # var: 2022-11-05T09:23:29
string(TIMESTAMP var UTC) # %Y-%m-%dT%H:%M:%SZ for UTC
message("var: ${var}") # var: 2022-11-05T01:23:29Z

string(TIMESTAMP var %B:%U)
message("var: ${var}") # var: November:44

      (7).UUID:基于<namespace>(其本身必须是有效的UUID)和<name>的组合值的哈希创建一个通用唯一标识符(GUID)。哈希算法可以是MD5或SHA1。UUID的格式为:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,其中每个x代表一个小写十六进制字符。如果需要,可以使用可选的UPPER标志请求大写表示。

string(UUID <output_variable> NAMESPACE <namespace> NAME <name> TYPE <MD5|SHA1> [UPPER])
string(UUID var NAMESPACE 34795e00-5a50-11ed-9b6a-0242ac120002 NAME beijing TYPE SHA1 UPPER)
message("var: ${var}") # var: B4383795-34FD-5079-BFC8-38E44E159A5D

string(UUID var NAMESPACE 34795e00-5a50-11ed-9b6a-0242ac120002 NAME beijing TYPE MD5)
message("var: ${var}") # var: fe7b8cbc-9a61-333e-aaad-b7acb502e9ac

      6.JSON:查询JSON字符串。如果给出了可选的ERROR_VARIABLE参数,则会在<error-var>中报告错误;并且<out-var>将设置为<member|index>-[<member|index>...]-NOTFOUND,或者如果没有相关path,则仅设置为NOTFOUND。如果发生error但ERROR_VARIABLE选项不存在,则会触发fatal error。如果没有发生error,<error-var>将设置为NOTFOUND。
      GET:通过给定的<member|index>从<json-string>获取元素。array和object元素将作为JSON字符串返回。boolean元素将作为ON或OFF返回。null元素将作为空字符串返回。number和string类型将作为字符串返回。
      TYPE:通过给定的<member|index>从<json-string>获取元素的类型。<out-var>将设置为NULL, NUMBER, STRING, BOOLEAN, ARRAY或OBJECT。
      LENGTH:通过给定的<member|index>从<json-string>获取元素的长度。需要元素为array或object类型。
      REMOVE:通过给定的<member|index>从<json-string>中删除一个元素。没有移除元素的JSON字符串将存储在<out-var>中。
      MEMBER:通过给定的<member|index>从<json-string>中获取第<index>成员的名称。需要元素为object类型。
      SET:设置<json-string>中的元素,将<member|index>设置为<value>。<value>应该是有效的JSON。
      EQUAL:比较<json-string1>和<json-string2>给出的两个JSON objects是否相等。<json-string1>和<json-string2>的内容应该是有效的JSON。如果认为JSON objects相等,则<out-var>将设置为true,否则设置为false。

set(str 
        "{
            \"name1\": \"csdn\",
            \"url1\": \"https://blog.csdn.net/fengbingchun\",
            \"name2\": \"github\",
            \"url2\": \"https://github.com/fengbingchun\"
        }"
)

string(JSON var ERROR_VARIABLE error_var GET ${str} "url1") # GET
message("var: ${var}") # var: https://blog.csdn.net/fengbingchun

string(JSON var ERROR_VARIABLE error_var TYPE ${str} "name1") # TYPE
message("var: ${var}") # var: STRING

string(JSON var ERROR_VARIABLE error_var LENGTH ${str} "name1") # LENGTH
message("var: ${var}, err: ${error_var}") # var: name1-NOTFOUND, err: LENGTH needs to be called with an element of type ARRAY or OBJECT, got STRING

string(JSON var ERROR_VARIABLE error_var REMOVE ${str} "name1") # REMOVE
message("var: ${var}") # var: {
                        # "name2" : "github",
                        # "url1" : "https://blog.csdn.net/fengbingchun",
                        # "url2" : "https://github.com/fengbingchun"
                        # }

string(JSON var ERROR_VARIABLE error_var MEMBER ${str} "name1") # MEMBER
message("var: ${var}, err: ${error_var}") # var: name1-NOTFOUND, err: expected an array index, got: 'name1'

string(JSON var ERROR_VARIABLE error_var SET ${str} "name1" ${str}) # SET
message("var: ${var}") # var: {
                        # "name1" : 
                        # {
                        # "name1" : "csdn",
                        # "name2" : "github",
                        # "url1" : "https://blog.csdn.net/fengbingchun",
                        # "url2" : "https://github.com/fengbingchun"
                        # },
                        # "name2" : "github",
                        # "url1" : "https://blog.csdn.net/fengbingchun",
                        # "url2" : "https://github.com/fengbingchun"
                        # }

string(JSON var ERROR_VARIABLE error_var EQUAL ${str} ${str}) # EQUAL
message("var: ${var}") # var: ON
string(JSON var ERROR_VARIABLE error_var EQUAL ${str} "{}") # EQUAL
message("var: ${var}") # var: OFF

      执行上述测试代码需要3个文件:build.sh, CMakeLists.txt, test_string.cmake

      build.sh内容如下:

#! /bin/bash

# supported input parameters(cmake commands)
params=(function macro cmake_parse_arguments \
		find_library find_path find_file find_program find_package \
		cmake_policy cmake_minimum_required project include \
		string list set)

usage()
{
	echo "Error: $0 needs to have an input parameter"

	echo "supported input parameters:"
	for param in ${params[@]}; do
		echo "  $0 ${param}"
	done

	exit -1
}

if [ $# != 1 ]; then
	usage
fi

flag=0
for param in ${params[@]}; do
	if [ $1 == ${param} ]; then
		flag=1
		break
	fi
done

if [ ${flag} == 0 ]; then
	echo "Error: parameter \"$1\" is not supported"
	usage
	exit -1
fi

if [[ ! -d "build" ]]; then
	mkdir build
	cd build
else
	cd build
fi

echo "==== test $1 ===="
cmake -DTEST_CMAKE_FEATURE=$1 ..

      CMakeLists.txt内容如下:

cmake_minimum_required(VERSION 3.22)
project(cmake_feature_usage)

message("#### current cmake version: ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}")
include(test_${TEST_CMAKE_FEATURE}.cmake)
message("==== test finish ====")

      test_string.cmake:为上面所有示例代码

      可能的执行结果如下图所示:

      GitHub: https://github.com/fengbingchun/Linux_Code_Test

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐