{"id":22404391,"url":"https://github.com/ascentis/mssql-regex","last_synced_at":"2025-10-30T18:47:39.530Z","repository":{"id":43343264,"uuid":"269412900","full_name":"Ascentis/mssql-regex","owner":"Ascentis","description":"Simple package allowing to use CLR RegEx within MSSQL","archived":false,"fork":false,"pushed_at":"2022-07-06T18:55:28.000Z","size":397,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-27T01:16:37.555Z","etag":null,"topics":["clr-regex","dotnet","mssql","mssql-database","mssql-regex","regex","regular-expression"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Ascentis.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}},"created_at":"2020-06-04T16:42:49.000Z","updated_at":"2022-07-06T18:52:05.000Z","dependencies_parsed_at":"2022-07-08T04:56:52.362Z","dependency_job_id":null,"html_url":"https://github.com/Ascentis/mssql-regex","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ascentis%2Fmssql-regex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ascentis%2Fmssql-regex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ascentis%2Fmssql-regex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ascentis%2Fmssql-regex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Ascentis","download_url":"https://codeload.github.com/Ascentis/mssql-regex/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245761303,"owners_count":20667895,"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":["clr-regex","dotnet","mssql","mssql-database","mssql-regex","regex","regular-expression"],"created_at":"2024-12-05T10:12:46.278Z","updated_at":"2025-10-30T18:47:34.479Z","avatar_url":"https://github.com/Ascentis.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mssql-regex\n\nThis package allows to use CLR RegEx class within MSSQL.\n\nThe package caches compiled Regex objects based on regex pattern and options parameter when specific version of the APIs is used.\nRegex objects are taken from the cache, used and returned back to the cache. By default they have a TTL of 5 minutes.\nThere's an initial cost upon executing a new regex as the regex expression is compiled into intermediate language opcodes and cached for reuse.\n\nThe functions return either a scalar string value or they return a table of strings containing each match.\n\nThere's a cleanup timer that runs every 10 seconds and it will cleanup all regex stacks not used in the last 5 minutes.\n\nThe library provides a set of functions to inspect the status of the cache and the number of executions performed since the library was loaded.\nMethods to reset the stats are provided.\n\nFor general reference on regular expression language as supported by Microsoft see: https://docs.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-language-quick-reference\n\nFor reference on Regex class see: https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex?view=netframework-4.6.1\n\nNuget repo with packaged up ready made .sql scripts: https://www.nuget.org/packages/Ascentis.RegExSQL/\n\nIMPORTANT: Please notice when installing this package in production you will want to run the following command in your database:\n\n```sql\nGRANT UNSAFE ASSEMBLY TO \"your_login\"\n```\n\nIt's also required to have CLR enabled in the target database:\n\n```sql\nEXEC sp_configure 'clr enabled', 1\nRECONFIGURE\n```\n\nYou need to run that command against all logins that may need to load this assembly, otherwise you will end up with warnings in the SQL logs each time this assembly is used given the fact it's marked unsafe.\n\n\n### Functions exposed:\n\n#### Matching functions returning a scalar value:\n```sql\nCREATE FUNCTION RegExIsMatch(\n    @input nvarchar(max), \n    @pattern nvarchar(max)) RETURNS bit\nCREATE FUNCTION RegExIsMatchWithOptions(\n    @input nvarchar(max), \n    @pattern nvarchar(max), \n    @options int) RETURNS bit\nCREATE FUNCTION RegExMatch(\n    @input nvarchar(max), \n    @pattern nvarchar(max)) RETURNS nvarchar(max)\nCREATE FUNCTION RegExMatchWithOptions(\n    @input nvarchar(max), \n    @pattern nvarchar(max), \n    @options int) RETURNS nvarchar(max)\nCREATE FUNCTION RegExMatchIndexed(\n    @input nvarchar(max), \n    @pattern nvarchar(max), \n    @index int) RETURNS nvarchar(max)\nCREATE FUNCTION RegExMatchIndexedWithOptions(\n    @input nvarchar(max), \n    @pattern nvarchar(max), \n    @index int, \n    @options int) RETURNS nvarchar(max)\nCREATE FUNCTION RegExMatchGroup(\n    @input nvarchar(max),\n    @pattern nvarchar(max),\n    @group int) RETURNS nvarchar(max)\nCREATE FUNCTION RegExMatchGroupWithOptions(\n    @input nvarchar(max),\n    @pattern nvarchar(max),\n    @group int,\n    @options int) RETURNS nvarchar(max)\nCREATE FUNCTION RegExMatchGroupIndexed(\n    @input nvarchar(max),\n    @pattern nvarchar(max),\n    @group int,\n    @index int) RETURNS nvarchar(max)\nCREATE FUNCTION RegExMatchGroupIndexedWithOptions(\n    @input nvarchar(max),\n    @pattern nvarchar(max),\n    @group int,\n    @index int,\n    @options int) RETURNS nvarchar(max)\n```\n\n#### Replacement functions\n```sql\nCREATE FUNCTION RegExReplace(\n    @input nvarchar(max),\n    @pattern nvarchar(max),\n    @replacement nvarchar(max)) RETURNS nvarchar(max)\nCREATE FUNCTION RegExReplaceWithOptions(\n    @input nvarchar(max),\n    @pattern nvarchar(max),\n    @replacement nvarchar(max),\n    @options int) RETURNS nvarchar(max)\nCREATE FUNCTION RegExReplaceCount(\n    @input nvarchar(max),\n    @pattern nvarchar(max),\n    @replacement nvarchar(max),\n    @count int) RETURNS nvarchar(max)\nCREATE FUNCTION RegExReplaceCountWithOptions(\n    @input nvarchar(max),\n    @pattern nvarchar(max),\n    @replacement nvarchar(max),\n    @count int,\n    @options int) RETURNS nvarchar(max)\n```\n\n#### String splitting functions\n```sql\nCREATE FUNCTION RegExSplit(\n    @input nvarchar(max),\n    @pattern nvarchar(max)) RETURNS TABLE (ITEM NVARCHAR(MAX))\nCREATE FUNCTION RegExSplitWithOptions(\n    @input nvarchar(max),\n    @pattern nvarchar(max),\n    @options int) RETURNS TABLE (ITEM NVARCHAR(MAX))\n```\n\n#### Matching functions returning all matches as a table\n```sql\nCREATE FUNCTION RegExMatches(\n    @input nvarchar(max),\n    @pattern nvarchar(max)) RETURNS TABLE (ITEM NVARCHAR(MAX))\nCREATE FUNCTION RegExMatchesWithOptions(\n    @input nvarchar(max),\n    @pattern nvarchar(max),\n    @options int) RETURNS TABLE (ITEM NVARCHAR(MAX))\nCREATE FUNCTION RegExMatchesGroup(\n    @input nvarchar(max),  \n    @pattern nvarchar(max),\n    @group int) RETURNS TABLE (ITEM NVARCHAR(MAX))\nCREATE FUNCTION RegExMatchesGroups(\n    @input nvarchar(max),  \n    @pattern nvarchar(max)) RETURNS TABLE (\n        MatchNum int,\n        GrpNum int,\n        GrpName nvarchar(255),\n        Item NVARCHAR(MAX))\nCREATE FUNCTION RegExMatchesGroupWithOptions(\n    @input nvarchar(max),\n    @pattern nvarchar(max),\n    @group int,\n    @options int) RETURNS TABLE (ITEM NVARCHAR(MAX))\nCREATE FUNCTION RegExMatchesGroupsWithOptions(\n    @input nvarchar(max),\n    @pattern nvarchar(max),    \n    @options int) RETURNS TABLE (\n        MatchNum int,\n        GrpNum int,\n        GrpName nvarchar(255),\n        Item NVARCHAR(MAX))\n```\n\n#### Escape and unescape string functions\n```sql\nCREATE FUNCTION RegExEscape(@input nvarchar(max)) RETURNS NVARCHAR(MAX)\nCREATE FUNCTION RegExUnescape(@input nvarchar(max)) RETURNS NVARCHAR(MAX)\n```\n\n#### Statistic and diagnostics collection functions\n```sql\nCREATE FUNCTION RegExCachedCount() RETURNS INT\nCREATE FUNCTION RegExClearCache() RETURNS INT\nCREATE FUNCTION RegExExecCount() RETURNS BIGINT\nCREATE FUNCTION RegExCacheHitCount() RETURNS BIGINT\nCREATE FUNCTION RegExExceptionCount() RETURNS BIGINT\nCREATE FUNCTION RegExResetExecCount() RETURNS BIGINT\nCREATE FUNCTION RegExResetCacheHitCount() RETURNS BIGINT\nCREATE FUNCTION RegExResetExceptionCount() RETURNS BIGINT\nCREATE FUNCTION RegExSetCacheEntryExpirationMilliseconds(\n    @cacheEntryExpirationMilliseconds int) RETURNS INT\nCREATE FUNCTION RegExCacheList() RETURNS TABLE (\n    PATTERN NVARCHAR(MAX), \n    OPTIONS INT, \n    CACHEREGEXCOUNT INT,\n    TTL INT\n)\n```\n\n#### Enum used for regex functions that receive @options parameter:\n\n```CSharp\npublic enum RegexOptions\n  {\n    /// Specifies that no options are set. For more information about the default behavior\n    /// of the regular expression engine, see the \"Default Options\" section in the \n    /// Regular Expression Options topic.\n     None = 0,\n\n    /// Specifies case-insensitive matching. For more information, see the \n    /// \"Case-Insensitive Matching \" section in the Regular Expression Options topic.\n     IgnoreCase = 1,\n\n    /// Multiline mode. Changes the meaning of ^ and $ so they match at the beginning \n    /// and end, respectively, of any line, and not just the beginning and end of the \n    /// entire string. For more information, see the \"Multiline Mode\" section in the \n    /// Regular Expression Options topic. \n     Multiline = 2,\n\n    /// Specifies that the only valid captures are explicitly named or numbered groups \n    /// of the form. \n    /// This allows unnamed parentheses to act as noncapturing groups without the \n    /// syntactic clumsiness of the expression (?:…). For more information, see the \n    /// \"Explicit Captures Only\" section in the Regular Expression Options topic. \n     ExplicitCapture = 4,\n\n    /// Specifies that the regular expression is compiled to an assembly. This yields \n    /// faster execution but increases startup time. \n    // This value should not be assigned to the property when calling the method. \n    /// For more information, see the \"Compiled Regular Expressions\" section in the \n    /// Regular Expression Options topic. \n     Compiled = 8,\n\n    /// Specifies single-line mode. Changes the meaning of the dot (.) so it matches \n    /// every character (instead of every character except \\n). \n    /// For more information, see the \"Single-line Mode\" section in the Regular Expression\n    /// Options topic. \n     Singleline = 16, // 0x00000010\n\n    /// Eliminates unescaped white space from the pattern and enables comments marked with #. \n    /// However, this value does not affect or eliminate white space in , numeric , \n    /// or tokens that mark the beginning of individual . For more information, see the \n    /// \"Ignore White Space\" section of the Regular Expression Options topic. \n     IgnorePatternWhitespace = 32, // 0x00000020\n\n    /// Specifies that the search will be from right to left instead of from left to right. \n    /// For more information, \n    /// see the \"Right-to-Left Mode\" section in the Regular Expression Options topic. \n     RightToLeft = 64, // 0x00000040\n\n    /// Enables ECMAScript-compliant behavior for the expression. This value can be used only \n    /// in conjunction with the and values. The use of this value with any other values results \n    /// in an exception.\n    /// For more information on the option, see the \"ECMAScript Matching Behavior\" section in the \n    /// Regular Expression Options topic. \n     ECMAScript = 256, // 0x00000100\n\n    /// Specifies that cultural differences in language is ignored. For more information, \n    /// see the \"Comparison Using the Invariant Culture\" section in the Regular Expression\n    /// Options topic.\n     CultureInvariant = 512, // 0x00000200\n  }\n```\n\nExample SQL to parse a table of key-value pairs, separated by commas and rows separates by semi-colons.\nThe example returns two columns: first column represent values for key named \"key1\" while the second column shows values for key named \"key2\".\n\n**Some notes on the SQL and the regex used in the example:**\n\nPlease notice that repeated values for the same key within a row are handled by respecting the last value found in the input string with\none exception: null values. If you enter as an input like \"key_n=\" (a blank value for key key_n_) it will be ignored by the handling SQL.\nThe group name 'sc' represents the row separator match.\n\n```sql\nSELECT Key1, Key2\nFROM (\t\n    SELECT DISTINCT RowGrp, GrpName, FIRST_VALUE(Item) OVER (PARTITION BY RowGrp, GrpName ORDER BY MatchNum DESC) AS Item\n    FROM (\n        SELECT MatchNum, GrpName, Item, SUM(RowGrp) OVER (ORDER BY MatchNum, GrpName) RowGrp\t\n        FROM (\n            SELECT MatchNum, GrpName, Item, IIF(GrpName = 'sc' AND Item = ';', 1, 0) RowGrp\n            FROM dbo.RegExMatchesGroups('key1=1,key2=2,key1=5;key2=3,key1=10;key1=4;', \n                                        '(?:(?:key1=(?\u003ckey1\u003e\\d+),?)*(?:key2=(?\u003ckey2\u003e\\d+),?)*)(?\u003csc\u003e;)?')\n            WHERE Item \u003c\u003e '' AND GrpName IN ('key1', 'key2', 'sc')\n        ) _\n    ) _\n    WHERE GrpName \u003c\u003e 'sc'\n) _\nPIVOT (\n    MAX(Item) FOR GrpName IN (key1, key2)\n) _\n```\n\nExample of using RegEx to parse a file with key-value pairs separated by a delimiter and a further delimiter to split rows. Please notice the example also includes code that shows how to build the regex dynamically given the target list of \"fields\" to be split.\n\n```sql\n/* \n   This example code parses a delimiter separated input string into key-value pairs and returns a table with rows\n   separated by a defined \"row separator\".\n   The T-SQL part of the code is an example how to build the regex dynamically taking as input the field list, the \n   pattern used for detecting values, the key-value pair separator and the row separator.\n*/\n\n-- Input variables\nDECLARE @fieldsList NVARCHAR(255) = 'key1,key2';\nDECLARE @valuePattern NVARCHAR(255) = '\\d+';\nDECLARE @kvpSeparator NVARCHAR(255) = ',';\nDECLARE @rowSeparator NVARCHAR(255) = ';';\n\n-- Internal variables to build regex\nDECLARE fields CURSOR FOR SELECT * FROM dbo.RegExSplit(@fieldsList, ',');\nDECLARE @field NVARCHAR(255);\nDECLARE @regex NVARCHAR(255) = '(';\n\nOPEN fields;\n\nFETCH NEXT FROM fields INTO @field;\nWHILE @@FETCH_STATUS = 0\nBEGIN\n    SET @regex = @regex + CONCAT('(?\u003c', @field, '\u003e(?\u003c=', @field, '=)', @valuePattern, '(?=', @kvpSeparator, ')?)*');\n    FETCH NEXT FROM fields INTO @field;\nEND;\n\nSET @regex = @regex + CONCAT(')(?\u003csc\u003e', @rowSeparator, '(?=.+))?');\nCLOSE fields;\nDEALLOCATE fields;\n\n/*\n  RegEx generated above looks like this:\n\n  ((?\u003ckey1\u003e(?\u003c=key1=)\\d+(?=,)?)*(?\u003ckey2\u003e(?\u003c=key2=)\\d+(?=,)?)*)(?\u003csc\u003e;(?=.+))?\n\n  Notice that in order to fetch other fields than key1 and key2 it's necessary to modify the input variable @fieldsList\n  and also the SQL below adding the extra fields to the top SELECT, the second level SELECT clauses and the PIVOT clause.\n*/\n\nSELECT MAX(Key1) Key1, MAX(Key2) Key2\nFROM (\n    SELECT RowGrp, Key1, Key2\n    FROM (\t\t\n        SELECT GrpName, Item, SUM(RowGrp) OVER (ORDER BY MatchNum, GrpName) RowGrp\n        FROM (\n            SELECT MatchNum, GrpName, Item, IIF(GrpName = 'sc' AND Item = ';', 1, 0) RowGrp\n            FROM dbo.RegExMatchesGroups('key1=1,key2=2,key1=5;key2=3,key1=10;key1=4;key3=453,key1=34,key2=546', @regex)\n        ) _\n    ) _\n    PIVOT (\n        MAX(Item) FOR GrpName IN (key1, key2)\n    ) _\n) _\nGROUP BY RowGrp\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fascentis%2Fmssql-regex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fascentis%2Fmssql-regex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fascentis%2Fmssql-regex/lists"}