如何在CMake中检查字符串是否仅由ASCII字符组成?

时间:2019-01-11 17:01:33

标签: string cmake character-encoding

我们正在使用CMake来编译我们的软件库。问题是,团队中有几个新人被接受,他们在文件/文件夹名称中使用变音符号。

CMake Generators通常会错误地读取诸如á,ř,š,ě,ž之类的字符,随后构建会因一些晦涩的行为而失败(创建名称混乱的新文件夹等)。


我的问题

  1. 是否有任何方法可以修改CMake的行为以接受这些字符?我对CMAKE_CURRENT_LIST_DIR的价值特别感兴趣。
  2. 如果点1不可能,是否有任何方法可以检查字符串以检测那些非ASCII字符并随后引发错误消息?

1 个答案:

答案 0 :(得分:0)

  1. 不是我所知道的,我也找不到任何东西。
  2. 是的。它不是很漂亮,但是下面的示例检查输入字符串中是否包含非法字符,如果找到非法字符,则会引发构建错误。在这个简单的示例中,它允许A-Z, a-z, 0-9, '\', '/', '-', '_', ':' and ' ' (space)

此特定解决方案的分步说明可能是:

  • 设置有效的特殊字符(应由用户通过参数指定)
  • 获取输入长度并减去1(从零开始的索引)
  • 迭代[i..length-of-string - 1]并从_name的那个位置获取相应的字符
  • 尝试将字符与A-Za-z匹配,如果找到,请转到下一个字符
  • 尝试将字符与0-9匹配,如果找到,请转到下一个字符
  • 尝试将字符与任何指定的特殊字符匹配,如果找到则转到下一个字符
  • 引发构建错误,因为当前字符不是有效字符
#
# validate_name(<name>)
#   Checks if the specified string consists of legal ASCII characters.
#   If an illegal character is found, then a build error is produced.
#   Legal characters are: A-Z, a-z, 0-9 and '\', '/', '-', '_', ':' and ' '.
#
#   _name:    The string to examine
#
#   Example: validate_name("C:\\foo\\bar")
#            validate_name("/home/user/code/project")
#
function(validate_name _name)
    # For simplicity, set all valid special characters here.
    set(valid_specials "\\\\/-_: ")
    string(LENGTH "${_name}" name_length)
    math(EXPR name_length "${name_length}-1")
    foreach(i RANGE 0 ${name_length})
        # Get next character.
        string(SUBSTRING "${_name}" ${i} 1 current_char)
        # Convert said character to lowercase. This way we don't have to consider
        # A-Z explicitly.
        string(TOLOWER ${current_char} current_char)
        # Is it A-Z or a-z?
        if (NOT (("${current_char}" STRLESS "a") OR ("${current_char}" STRGREATER "z")))
            # It's A-Z or a-z.
            continue()
        endif()
        # Is it a number?
        if (NOT (("${current_char}" STRLESS "0") OR ("${current_char}" STRGREATER "9")))
            # It's a number.
            continue()
        endif()
        # Is it a valid "special" character?
        string(FIND "${valid_specials}" "${current_char}" valid_special_found)
        if (valid_special_found GREATER -1)
            continue()
        endif()
        message(FATAL_ERROR "'${current_char}' is not a legal character in this context.")
    endforeach()
endfunction()

如果要减小代码的大小,可以将所有允许的字符放在单个字符串中并使用string(FIND ...),就像对特殊字符所做的操作一样。无论如何,性能并不重要。我这样做是为了让您知道STRLESS等。

最后,对于您的情况,您可以使用validate_name(${CMAKE_CURRENT_LIST_DIR})

另一种可能的解决方案是仅使用正则表达式:

set(NAME "home/user/path")
string(REGEX MATCH "[A-Za-z0-9 \\\\/:_-]*" MATCH "${NAME}")
if (NOT "${MATCH}" STREQUAL "${NAME}")
    message(FATAL_ERROR "Illegal character(s) found.")
endif()

如果找到该规则未定义的任何字符,这将产生一个不同的字符串。如果字符串有效,则MATCH == NAME。请注意,如果第一个字符不合法,CMake将抛出自己的错误。我远不是正则表达式专家,所以我敢肯定有一个更优雅的解决方案。

无论如何,我认为这至少应该让您入门。让我知道是否需要进一步说明。