Regexing for 2 periods? `..`

I’m trying to detecting when a path contains .. For example:

D:/foobar/../

However I can’t seem to write the correct regex.

# regex.cmake
cmake_minimum_required(VERSION 3.21)

if ("D:/foobar" MATCHES "\.\.")
    message(STATUS "${CMAKE_MATCH_0}")
endif()

if ("D:/foobar/../" MATCHES "\.\.")
    message(STATUS "${CMAKE_MATCH_0}")
endif()

I run this regex and it somehow matches in both cases.

> cmake -P .\regex.cmake
-- D:
-- D:

Why is this happening?

The docs say you can use backslash to escape the . character:

The documentation is a bit misleading. You basically need to escape “twice”. Once for the CMake parser itself, and once for the regex engine.

For instance, if you write

if ("D:\\foobar" MATCHES "\\")
    message(STATUS "${CMAKE_MATCH_0}")
endif()

then the regex engine actually gets \, which is not a valid regex, and you get an error like:

RegularExpression::compile(): Trailing backslash.
RegularExpression::compile(): Error in compile.
CMake Error at D:/dev/CMExt/regex.cmake:3 (if):
  if given arguments:

    "D:\\foobar" "MATCHES" "\\"

  Regular expression "\" cannot compile

In your case, you need to write:

if ("D:/foobar/../" MATCHES "\\.\\.")
    message(STATUS "${CMAKE_MATCH_0}")
endif()

I hope this helps!

3 Likes

As an alternative you can use a bracket argument [[\.\.]] intead of a quoted argument "\\.\\.".
This makes writing RegExes simplier.

This is mentioned in the last sentence of the Regex Specification. Perhaps the docs should mention the right escaping at the top of the chapter.

2 Likes