Repository: scikit-build/scikit-build-core (python)

Issue:
Regex support for more complex structures?
Currently, something like this is hard to capture:

```cpp
#define NB_VERSION_MAJOR 2
#define NB_VERSION_MINOR 0
#define NB_VERSION_PATCH 1
#define NB_VERSION_DEV   1 // A value > 0 indicates a development release
```

As we only have a `{value}` field.

Pull request description:
feat: add `remove=` postprocess to regex
This adds the ability to post-process regex to remove "dev0" or similar. Closes #765.


Patch:
diff --git a/docs/configuration.md b/docs/configuration.md
index 7107659..e245e40 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -565,7 +565,8 @@ You can set a custom regex with `regex=`. By default when targeting version, you
 get a reasonable regex for python files,
 `'(?i)^(__version__|VERSION)(?: ?\: ?str)? *= *([\'"])v?(?P<value>.+?)\2'`.
 You can set `result` to a format string to process the matches; the default is
-`"{value}"`. A more complex example:
+`"{value}"`. You can also specify a regex for `remove=` which will strip any
+matches from the final result. A more complex example:
 
 ```toml
 [tool.scikit-build.metadata.version]
@@ -574,15 +575,24 @@ input = "src/mypackage/version.hpp"
 regex = '''(?sx)
 \#define \w+ VERSION_MAJOR \w+ (?P<major>\d+) .*?
 \#define \w+ VERSION_MINOR \w+ (?P<minor>\d+) .*?
-\#define \w+ VERSION_PATCH \w+ (?P<patch>\d+)
+\#define \w+ VERSION_PATCH \w+ (?P<patch>\d+) .*?
+\#define \w+ VERSION_DEV \w+ (?P<dev>\d+) .*?
 '''
-result = "{major}.{minor}.{patch}"
+result = "{major}.{minor}.{patch}dev{dev}"
+remove = "dev0"
 ```
 
+This will remove the "dev" tag when it is equal to 0.
+
 ```{versionadded} 0.5
 
 ```
 
+```{versionchanged} 0.10
+
+Support for `result` and `remove` added.
+```
+
 :::
 
 ### Writing metadata
diff --git a/src/scikit_build_core/metadata/regex.py b/src/scikit_build_core/metadata/regex.py
index 6963498..fdaf118 100644
--- a/src/scikit_build_core/metadata/regex.py
+++ b/src/scikit_build_core/metadata/regex.py
@@ -14,7 +14,7 @@ def __dir__() -> list[str]:
     return __all__
 
 
-KEYS = {"input", "regex", "result"}
+KEYS = {"input", "regex", "result", "remove"}
 
 
 def dynamic_metadata(
@@ -46,6 +46,7 @@ def dynamic_metadata(
     )
     result = settings.get("result", "{value}")
     assert isinstance(result, str)
+    remove = settings.get("result", "")
 
     with Path(input_filename).open(encoding="utf-8") as f:
         match = re.search(regex, f.read(), re.MULTILINE)
@@ -54,4 +55,7 @@ def dynamic_metadata(
         msg = f"Couldn't find {regex!r} in {input_filename}"
         raise RuntimeError(msg)
 
-    return result.format(*match.groups(), **match.groupdict())
+    retval = result.format(*match.groups(), **match.groupdict())
+    if remove:
+        retval = re.sub(remove, "", retval)
+    return retval


Test patch:
diff --git a/tests/test_dynamic_metadata.py b/tests/test_dynamic_metadata.py
index c3bc9ab..c1ce856 100644
--- a/tests/test_dynamic_metadata.py
+++ b/tests/test_dynamic_metadata.py
@@ -308,3 +308,42 @@ def test_multipart_regex(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Non
     )
 
     assert version == "1.2.3dev1"
+
+
+@pytest.mark.parametrize("dev", [0, 1])
+def test_regex_remove(
+    tmp_path: Path, monkeypatch: pytest.MonkeyPatch, dev: int
+) -> None:
+    d = tmp_path / "test_multidev_regex"
+    d.mkdir()
+    monkeypatch.chdir(d)
+
+    with Path("version.hpp").open("w") as f:
+        f.write(
+            textwrap.dedent(
+                f"""\
+                #define VERSION_MAJOR 1
+                // Comment
+                #define VERSION_MINOR 2
+                #define VERSION_PATCH 3
+                #define VERSION_DEV {dev}
+                """
+            )
+        )
+
+    version = regex.dynamic_metadata(
+        "version",
+        {
+            "input": "version.hpp",
+            "regex": r"""(?sx)
+            \#define \s+ VERSION_MAJOR \s+ (?P<major>\d+) .*?
+            \#define \s+ VERSION_MINOR \s+ (?P<minor>\d+) .*?
+            \#define \s+ VERSION_PATCH \s+ (?P<patch>\d+) .*?
+            \#define \s+ VERSION_DEV \s+ (?P<dev>\d+)
+            """,
+            "result": "{major}.{minor}.{patch}dev{dev}",
+            "remove": r"dev0",
+        },
+    )
+
+    assert version == "1.2.3dev1" if dev else "1.2.3"