从CMake中的REGEX REPLACE中排除包含特定字符串的行

时间:2015-05-13 23:20:59

标签: regex replace cmake ogre

这是我的第一篇文章,但我多年来一直在使用StackOverflow。谢谢你每次帮助我。

我在CMake中编写一个脚本,该脚本应该重写.cfg文件的一部分(它是来自Ogre 3D引擎的resources.cfg文件),以便:

  • 使用cmake运行config时,根据系统设置绝对路径
  • 安装时,所有文件都被复制到文件夹中,相对路径设置为

我将只关注第一部分,因为它们都是相似的。这是我正在处理的资源文件:

# Resources required by the sample browser and most samples.
[Essential]
Zip=stufftochange/media/packs/SdkTrays.zip

# Resource locations to be added to the default path
[General]
FileSystem=../media #local
FileSystem=stufftochange/media/materials/scripts
FileSystem=stufftochange/media/materials/textures
FileSystem=stufftochange/media/models
FileSystem=stufftochange/media/materials/programs/HLSL_Cg 
FileSystem=stufftochange/media/materials/programs/GLSL

我目前的策略是只有没有#local标识符的行应受REGEX REPLACE语句的影响。 我目前的代码是:

file(READ ${CMAKE_SOURCE_DIR}/cfg/resources.cfg RESOURCES_FILE)
string(REGEX REPLACE
    "/media"
    "${OGRE_HOME_BACKSLASHES}/media"
    RESOURCES_FILE_MODIFIED ${RESOURCES_FILE})
file(WRITE ${CMAKE_SOURCE_DIR}/cfg/resources.cfg ${RESOURCES_FILE_MODIFIED})

基本上取代了所有/media次出现。只有当stufftochange不在行的末尾时,我才需要替换media(可以是字符串#local之前的任何内容)。我尝试以多种方式修改匹配表达式,但是,当我这样做时,只有第一行和最后一行被正确替换。我怀疑它与行结尾有关。

这些是我试过的一些表达方式,没有运气:

([^ #]*)=[^ ]*/media([^#\n$]*)
=[^ ]*/media([^#\n$]*)
/media([^# ]*)
/media([^#\n ]*)

当然我使用\\1\\2来保存我想要保留的字符串部分。

我在google和stackoverflow上做了一些搜索,但找不到使用CMake正则表达式替换的正确解决方案或指南(文档非常基本)。知道我的圣杯比赛表达会是什么吗?

1 个答案:

答案 0 :(得分:6)

CMake的正则表达式语法和文档非常有限。我倾向于将文件的内容转换为字符串列表,每个字符串都是文件中的一行。迭代这些使正则表达式更简单:

set(SourceFile "${CMAKE_SOURCE_DIR}/cfg/resources.cfg")
file(READ ${SourceFile} Contents)

# Set the variable "Esc" to the ASCII value 27 - basically something
# which is unlikely to conflict with anything in the file contents.
string(ASCII 27 Esc)

# Turn the contents into a list of strings, each ending with an Esc.
# This allows us to preserve blank lines in the file since CMake
# automatically prunes empty list items during a foreach loop.
string(REGEX REPLACE "\n" "${Esc};" ContentsAsList "${Contents}")

unset(ModifiedContents)
foreach(Line ${ContentsAsList})
  # Don't modify the line if it contains #local at the end.
  if(NOT "${Line}" MATCHES "#local${Esc}$")
    string(REGEX REPLACE "=.*/media" "=${OGRE_HOME_BACKSLASHES}/media" Line ${Line})
  endif()
  # Swap the appended Esc character back out in favour of a line feed
  string(REGEX REPLACE "${Esc}" "\n" Line ${Line})
  set(ModifiedContents "${ModifiedContents}${Line}")
endforeach()
file(WRITE ${SourceFile} ${ModifiedContents})

如果您不关心保留空行,可以使用file(STRINGS ...)读取文件,这样可以简化生活:

set(SourceFile "${CMAKE_SOURCE_DIR}/cfg/resources.cfg")
file(STRINGS ${SourceFile} Contents)

unset(ModifiedContents)
foreach(Line ${Contents})
  # Don't modify the line if it contains #local at the end.
  if(NOT "${Line}" MATCHES "#local$")
    string(REGEX REPLACE
        "=.*/media"
        "=${OGRE_HOME_BACKSLASHES}/media"
        Line ${Line})
  endif()
  set(ModifiedContents "${ModifiedContents}${Line}\n")
endforeach()
file(WRITE ${SourceFile} ${ModifiedContents})

可能有关CMake正则表达式语法的最佳描述可在string的文档中找到。