循环遍历字符串列表

时间:2014-07-27 22:45:07

标签: list foreach cmake

我想循环遍历字符串中给出的项目列表。根据CMake的要求,项目以分号分隔。以下

cmake_minimum_required(VERSION 2.8)

FOREACH(LETTER "a;b;c")
  MESSAGE("<<${LETTER}>>")
ENDFOREACH()

将字符串"a;b;c"解释为字符串文字。相反,在首先为变量分配"a;b;c"时,所有内容都按预期进行。

cmake_minimum_required(VERSION 2.8)

SET(MYLIST "a;b;c")
FOREACH(LETTER ${MYLIST})
  MESSAGE("<<${LETTER}>>")
ENDFOREACH()

这是循环列表的推荐方法还是有更优雅的解决方案?

2 个答案:

答案 0 :(得分:35)

你混淆的根源可能是CMake对引用字符串的特殊解释。

例如,以下所有内容都正确迭代字符串列表:

(1) foreach(LETTER a b c) [...]
(2) foreach(LETTER a;b;c) [...]
(3) set(MYLIST "a;b;c")
    foreach(LETTER ${MYLIST}) [...]

唯一不起作用的情况是

(4) foreach(LETTER "a;b;c") [...]

CMake's language manual for unquoted arguments中找到(1)(2)有效的原因:

  

不带引号的参数内容由连续块中的所有文本组成   允许或转义的字符。 Escape序列和变量   评估参考文献。结果值除以相同的值   方式列表分为元素。每个非空元素都被赋予   命令调用作为参数。因此,一个不带引号的论点可能会   作为零个或多个参数被赋予命令调用。

请注意,这与quoted arguments不同,set也评估转义序列和变量引用,但不进行列表扩展。这解释了(4)失败的原因。

现在有趣的问题是为什么(3)仍然成功。 {{3}}将接受单值和列表值参数。事实上,在结束)或其中一个关键字CACHEPARENT_SCOPE之前的所有内容都被视为值的一部分。因此,以下两个命令是等效的:

set(MYLIST "a;b;c")
set(MYLIST a;b;c)

在这两种情况下,MYLIST的值都为a;b;c(不含引号)。

当我们现在将${MYLIST}扩展为另一个命令时,您可以认为它执行了一个简单的字符串替换,其值为MYLIST,即a;b;c。然后,生成的命令将通过引用或不引用参数的规则进行扩展。也就是说,以下内容将起作用:

foreach(LETTER ${MYLIST}) [...]

虽然这不会:

foreach(LETTER "${MYLIST}") [...]

答案 1 :(得分:0)

首先,考虑您是否在 foreach 调用中键入所有值,例如 foreach (N 1 2 3),或者您是否想要扩展一个变量,例如 foreach (N ${MY_NUMBER_LIST})

虽然已接受的答案扩展了行上的变量,使代码注入成为可能(如果变量是在脚本之外设置的),但它仍然适用于大多数情况。

但是为了安全循环变量(不扩展),请尝试以下操作:

# My dummy data.
set (_my_list "A B C")
string (REPLACE " " ";" _my_list "${_my_list}")

# Actual looping.
foreach (my_entry IN LISTS _my_list)

    # All done! do something with ${my_entry}, for example:
    if (NOT my_entry IN_LIST _my_other_list)
        message(FATAL_ERROR "_my_list has ${my_entry} but _my_other_list does not!!")
    endif()

endforeach()