{"id":13419177,"url":"https://github.com/hanickadot/compile-time-regular-expressions","last_synced_at":"2025-09-27T10:32:05.217Z","repository":{"id":38848128,"uuid":"61965362","full_name":"hanickadot/compile-time-regular-expressions","owner":"hanickadot","description":"Compile Time Regular Expression in C++","archived":false,"fork":false,"pushed_at":"2024-09-21T17:36:49.000Z","size":2539,"stargazers_count":3305,"open_issues_count":99,"forks_count":181,"subscribers_count":67,"default_branch":"main","last_synced_at":"2024-09-21T17:53:13.860Z","etag":null,"topics":["awesome","compile-time","constexpr","cpp17","cpp20","header-only","pcre","regular-expression","template-udl"],"latest_commit_sha":null,"homepage":"https://twitter.com/hankadusikova","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hanickadot.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-06-25T23:17:18.000Z","updated_at":"2024-09-21T17:36:53.000Z","dependencies_parsed_at":"2024-04-25T16:45:47.922Z","dependency_job_id":"7250facb-c353-496c-ad1b-da0808212683","html_url":"https://github.com/hanickadot/compile-time-regular-expressions","commit_stats":{"total_commits":651,"total_committers":31,"mean_commits":21.0,"dds":0.2319508448540707,"last_synced_commit":"78ba3a3ddc6a977b0a46ad566876a6844eedb16a"},"previous_names":[],"tags_count":43,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hanickadot%2Fcompile-time-regular-expressions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hanickadot%2Fcompile-time-regular-expressions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hanickadot%2Fcompile-time-regular-expressions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hanickadot%2Fcompile-time-regular-expressions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hanickadot","download_url":"https://codeload.github.com/hanickadot/compile-time-regular-expressions/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219871985,"owners_count":16554477,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["awesome","compile-time","constexpr","cpp17","cpp20","header-only","pcre","regular-expression","template-udl"],"created_at":"2024-07-30T22:01:12.357Z","updated_at":"2025-09-27T10:32:05.188Z","avatar_url":"https://github.com/hanickadot.png","language":"C++","funding_links":[],"categories":["TODO scan for Android support in followings","Regular Expression","HarmonyOS","C++","C/C++程序设计","正则表达式"],"sub_categories":["Windows Manager","资源传输下载","物理学"],"readme":"# Compile Time Regular Expressions v3\n\n[![Build Status](https://github.com/hanickadot/compile-time-regular-expressions/actions/workflows/tests.yml/badge.svg)](https://github.com/hanickadot/compile-time-regular-expressions/actions/workflows/tests.yml)\n\nFast compile-time regular expressions with support for matching/searching/capturing during compile-time or runtime.\n\nYou can use the single header version from directory `single-header`. This header can be regenerated with `make single-header`. If you are using cmake, you can add this directory as subdirectory and link to target `ctre`.\n\nMore info at [compile-time.re](https://compile-time.re/)\n\n## What this library can do\n\n```c++\nctre::match\u003c\"REGEX\"\u003e(subject); // C++20\n\"REGEX\"_ctre.match(subject); // C++17 + N3599 extension\n```\n\n* Matching\n* Searching (`search` or `starts_with`)\n* Capturing content (named captures are supported too, but only with syntax `(?\u003cname\u003e...)`)\n* Back-Reference (`\\g{N}` syntax, and `\\1...\\9` syntax too)\n* Multiline support (with `multiline_`) functions\n* Unicode properties and UTF-8 support\n\nThe library is implementing most of the PCRE syntax with a few exceptions:\n\n* callouts\n* comments\n* conditional patterns\n* control characters (`\\cX`)\n* match point reset (`\\K`)\n* named characters\n* octal numbers\n* options / modes\n* subroutines\n* unicode grapheme cluster (`\\X`)\n\nMore documentation on [pcre.org](https://www.pcre.org/current/doc/html/pcre2syntax.html).\n\n### Unknown character escape behaviour\n\nNot all escaped characters are automatically inserted as self, behaviour of the library is escaped characters are with special meaning, unknown escaped character is a syntax error.\n\nExplicitly allowed character escapes which insert only the character are:\n\n```\\-\\\"\\\u003c\\\u003e```\n\n## Basic API\n\nThis is approximated API specification from a user perspective (omitting `constexpr` and `noexcept` which are everywhere, and using C++20 syntax even the API is C++17 compatible):\n```c++\n// look if whole input matches the regex:\ntemplate \u003cfixed_string regex\u003e auto ctre::match(auto Range \u0026\u0026) -\u003e regex_results;\ntemplate \u003cfixed_string regex\u003e auto ctre::match(auto First \u0026\u0026, auto Last \u0026\u0026) -\u003e regex_results;\n\n// look if input contains match somewhere inside of itself:\ntemplate \u003cfixed_string regex\u003e auto ctre::search(auto Range \u0026\u0026) -\u003e regex_results;\ntemplate \u003cfixed_string regex\u003e auto ctre::search(auto First \u0026\u0026, auto Last \u0026\u0026) -\u003e regex_results;\n\n// check if input starts with match (but doesn't need to match everything):\ntemplate \u003cfixed_string regex\u003e auto ctre::starts_with(auto Range \u0026\u0026) -\u003e regex_results;\ntemplate \u003cfixed_string regex\u003e auto ctre::starts_with(auto First \u0026\u0026, auto Last \u0026\u0026) -\u003e regex_results;\n\n// result type is deconstructible into a structured bindings\ntemplate \u003c...\u003e struct regex_results {\n\toperator bool() const; // if it's a match\n\tauto to_view() const -\u003e std::string_view; // also view()\n\tauto to_string() const -\u003e std::string; // also str()\n\toperator std::string_view() const; // also supports all char variants\n\texplicit operator std::string() const;\n\t\n\t// also size(), begin(), end(), data()\n\t\n\tsize_t count() const; // number of captures \n\ttemplate \u003csize_t Id\u003e const captured_content \u0026 get() const; // provide specific capture, whole regex_results is implicit capture 0\n};\n```\n\n### Range outputting API\n\n```c++\n// search for regex in input and return each occurrence, ignoring rest:\ntemplate \u003cfixed_string regex\u003e auto ctre::range(auto Range \u0026\u0026) -\u003e range of regex_result;\ntemplate \u003cfixed_string regex\u003e auto ctre::range(auto First \u0026\u0026, auto Last \u0026\u0026) -\u003e range of regex_result;\n\n// return range of each match, stopping at something which can't be matched\ntemplate \u003cfixed_string regex\u003e auto ctre::tokenize(auto Range \u0026\u0026) -\u003e range of regex_result;\ntemplate \u003cfixed_string regex\u003e auto ctre::tokenize(auto First \u0026\u0026, auto Last \u0026\u0026) -\u003e range of regex_result;\n\n// return parts of the input split by the regex, returning it as part of content of the implicit zero capture (other captures are not changed, you can use it to access how the values were split):\ntemplate \u003cfixed_string regex\u003e auto ctre::split(auto Range \u0026\u0026) -\u003e regex_result;\ntemplate \u003cfixed_string regex\u003e auto ctre::split(auto First \u0026\u0026, auto Last \u0026\u0026) -\u003e range of regex_result;\n```\n\n### Functors\n\nAll the functions (`ctre::match`, `ctre::search`, `ctre::starts_with`, `ctre::range`, `ctre::tokenize`, `ctre::split`) are functors and can be used without parenthesis:\n\n```c++\nauto matcher = ctre::match\u003c\"regex\"\u003e;\nif (matcher(input)) ...\n```\n\n### Possible subjects (inputs)\n\n* `std::string`-like objects (`std::string_view` or your own string if it's providing `begin`/`end` functions with forward iterators)\n* pairs of forward iterators\n\n### Unicode support\n\nTo enable you need to include:\n\n* `\u003cctre-unicode.hpp\u003e`\n* or `\u003cctre.hpp\u003e` and `\u003cunicode-db.hpp\u003e`\n\nOtherwise you will get missing symbols if you try to use the unicode support without enabling it.\n\n## Supported compilers\n\n* clang 14.0+ (template UDL, C++17 syntax, C++20 cNTTP syntax)\n* xcode clang 15.0+ (template UDL, C++17 syntax, C++20 cNTTP syntax)\n* gcc 9.0+ (C++17 \u0026 C++20 cNTTP syntax)\n* MSVC 14.29+ (Visual Studio 16.11+) (C++20 cNTTP syntax) \n\n### Template UDL syntax\n\nThe compiler must support extension N3599, for example as GNU extension in gcc (not in GCC 9.1+) and clang.\n\n```c++\nconstexpr auto match(std::string_view sv) noexcept {\n    using namespace ctre::literals;\n    return \"h.*\"_ctre.match(sv);\n}\n```\n\nIf you need extension N3599 in GCC 9.1+, you can't use -pedantic. Also, you need to define macro `CTRE_ENABLE_LITERALS`.\n\n### C++17 syntax\n\nYou can provide a pattern as a `constexpr ctll::fixed_string` variable.\n\n```c++\nstatic constexpr auto pattern = ctll::fixed_string{ \"h.*\" };\n\nconstexpr auto match(std::string_view sv) noexcept {\n    return ctre::match\u003cpattern\u003e(sv);\n}\n```\n\n(this is tested in MSVC 15.8.8)\n\n### C++20 syntax\n\nCurrently, the only compiler which supports cNTTP syntax `ctre::match\u003cPATTERN\u003e(subject)` is GCC 9+.\n\n```c++\nconstexpr auto match(std::string_view sv) noexcept {\n    return ctre::match\u003c\"h.*\"\u003e(sv);\n}\n```\n\n## Examples\n\n### Extracting number from input\n\n```c++\nstd::optional\u003cstd::string_view\u003e extract_number(std::string_view s) noexcept {\n    if (auto m = ctre::match\u003c\"[a-z]+([0-9]+)\"\u003e(s)) {\n        return m.get\u003c1\u003e().to_view();\n    } else {\n        return std::nullopt;\n    }\n}\n```\n\n[link to compiler explorer](https://gcc.godbolt.org/z/5U67_e)\n\n### Extracting values from date\n\n```c++\nstruct date { std::string_view year; std::string_view month; std::string_view day; };\n\nstd::optional\u003cdate\u003e extract_date(std::string_view s) noexcept {\n    using namespace ctre::literals;\n    if (auto [whole, year, month, day] = ctre::match\u003c\"(\\\\d{4})/(\\\\d{1,2})/(\\\\d{1,2})\"\u003e(s); whole) {\n        return date{year, month, day};\n    } else {\n        return std::nullopt;\n    }\n}\n\n// static_assert(extract_date(\"2018/08/27\"sv).has_value());\n// static_assert((*extract_date(\"2018/08/27\"sv)).year == \"2018\"sv);\n// static_assert((*extract_date(\"2018/08/27\"sv)).month == \"08\"sv);\n// static_assert((*extract_date(\"2018/08/27\"sv)).day == \"27\"sv);\n```\n\n[link to compiler explorer](https://gcc.godbolt.org/z/x64CVp)\n\n### Using captures\n\n```c++\nauto result = ctre::match\u003c\"(?\u003cyear\u003e\\\\d{4})/(?\u003cmonth\u003e\\\\d{1,2})/(?\u003cday\u003e\\\\d{1,2})\"\u003e(s);\nreturn date{result.get\u003c\"year\"\u003e(), result.get\u003c\"month\"\u003e, result.get\u003c\"day\"\u003e};\n\n// or in C++ emulation, but the object must have a linkage\nstatic constexpr ctll::fixed_string year = \"year\";\nstatic constexpr ctll::fixed_string month = \"month\";\nstatic constexpr ctll::fixed_string day = \"day\";\nreturn date{result.get\u003cyear\u003e(), result.get\u003cmonth\u003e(), result.get\u003cday\u003e()};\n\n// or use numbered access\n// capture 0 is the whole match\nreturn date{result.get\u003c1\u003e(), result.get\u003c2\u003e(), result.get\u003c3\u003e()};\n```\n\n### Lexer\n\n```c++\nenum class type {\n    unknown, identifier, number\n};\n\nstruct lex_item {\n    type t;\n    std::string_view c;\n};\n\nstd::optional\u003clex_item\u003e lexer(std::string_view v) noexcept {\n    if (auto [m,id,num] = ctre::match\u003c\"([a-z]+)|([0-9]+)\"\u003e(v); m) {\n        if (id) {\n            return lex_item{type::identifier, id};\n        } else if (num) {\n            return lex_item{type::number, num};\n        }\n    }\n    return std::nullopt;\n}\n```\n\n[link to compiler explorer](https://gcc.godbolt.org/z/PKTiCC)\n\n### Range over input\n\nThis support is preliminary, probably the API will be changed.\n\n```c++\nauto input = \"123,456,768\"sv;\n\nfor (auto match: ctre::search_all\u003c\"([0-9]+),?\"\u003e(input))\n    std::cout \u003c\u003c std::string_view{match.get\u003c0\u003e()} \u003c\u003c \"\\n\";\n```\n\n### Unicode\n\n```c++\n#include \u003cctre-unicode.hpp\u003e\n#include \u003ciostream\u003e\n\n// needed if you want to output to the terminal\nstd::string_view cast_from_unicode(std::u8string_view input) noexcept {\n    return std::string_view(reinterpret_cast\u003cconst char *\u003e(input.data()), input.size());\n}\n\nint main() {\n    using namespace std::literals;\n    std::u8string_view original = u8\"Tu es un génie\"sv;\n\n    for (auto match: ctre::search_all\u003c\"\\\\p{Letter}+\"\u003e(original))\n        std::cout \u003c\u003c cast_from_unicode(match) \u003c\u003c std::endl;\n    return 0;\n}\n```\n\n[link to compiler explorer](https://godbolt.org/z/erTshe6sz)\n\n\n## Installing ctre using vcpkg\n\nYou can download and install ctre using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:\n\n```bash\ngit clone https://github.com/Microsoft/vcpkg.git\ncd vcpkg\n./bootstrap-vcpkg.sh\n./vcpkg integrate install\n./vcpkg install ctre\n```\n\nThe ctre port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.\n\n## Running tests (for developers)\n\nJust run `make` in root of this project.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhanickadot%2Fcompile-time-regular-expressions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhanickadot%2Fcompile-time-regular-expressions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhanickadot%2Fcompile-time-regular-expressions/lists"}