使用 .NET 正则表达式查找所有特殊标记
Finding all special tokens with .NET regular expressions
使用正则表达式,我需要收集 valid 顶级标记 {...}
并忽略引用字符串中的标记边界"..."
(包括可能的 ""
)。
简化样本:
TEXT{bbbbb}TEXT{cccc|{dddd}}TEXT{eeee|ff{gg}hh|ii{jj}"kk}{|{}ll""mm{nn}"oo|{pppp}}TEXT
预计有 3 场比赛:
{bbbbb}
{cccc|{dddd}}
{eeee|ff{gg}hh|ii{jj}"kk}{|{}ll""mm{nn}"oo|{pppp}}
请注意字符串 "kk}{|{}ll""mm{nn}"
的内容被忽略
每个标记都应遵循以下语法:
'{'<tokenName>[a1]['|'[a2|c1]('='|'<>')c2]['|'c3['|'c4]]'}'
其中 aX
是简单的正则表达式 ((,-?\d+(:.*)?|:.*)
),cX
可以包含匹配的 {
-}
、纯文本和字符串 "..."
其中 {
、}
、|
、""
等特殊字符被视为纯文本。
我不明白此正则表达式中需要的平衡和转义。对于初学者来说可能太难了。
其他详细信息:
我已经完成了部分解决方案,我的问题是平衡和引用。
我正在尝试创建包含在 input As String
中的扩展标记,它看起来类似于 format strings,但也允许条件评估。例如在文件名模板中使用这些标记,用户可以在批处理中配置文件名的自定义部分。令牌具有字母数字名称和格式部分(包括可选条件、真部分和假部分)。格式化部分可以在:
“本机格式”——从 String.Format()
得知,但字母数字名称而不是占位符 {0}
、{1}
、{2}
、.. .
正则表达式是 (,-?\d+(:.*)?|:.*)
.
示例:
,3
(转换为标准 {0,3}
)
:d
(转换为标准 {0:d}
)
-3:d
(转换为标准 {0,-3:d}
)
“复杂格式”——原生格式,
或固定文字 {0}
作为字符串 ...{0<native format>}...
的一部分上下文化
正则表达式是:"("
& nativeFormatSpec & "|.*({0.*}.*)*)"
.
示例:
-4:d
(仅限本机格式)
prefix {0,-4:d} & once more {0} suffix
被翻译成
. . . . String.Format("prefix {0,-4:d} "&}} once" more {0} suffix", value)
现在有效令牌的完整语法是:
'{'<tokenName>[quickFormat]['|'[complexFmt1]('='|'<>')value][complexFmt2|[complexFmt3]]'}'
我的代码使用了很多命名组,但正则表达式可能太简单了:
'*** matching token names (for later use as match.Group(groupName))
Const tokenGroup As String = NameOf(tokenGroup)
Const compareFormatGroup As String = NameOf(compareFormatGroup)
Const quickFormatGroup As String = NameOf(quickFormatGroup)
Const compareOperatorGroup As String = NameOf(compareOperatorGroup)
Const compareValueGroup As String = NameOf(compareValueGroup)
Const defaultFormatGroup As String = NameOf(defaultFormatGroup)
Const elseFormatGroup As String = NameOf(elseFormatGroup)
'*** subpatterns
Const nativeFormatSpec As String = "(,-?\d+(:.*)?|:.*)"
Const complexFormatSpec As String = "(" & nativeFormatSpec & "|.*({0.*}.*)*)" 'value allowing one token {0} multiple times
Dim matches As MatchCollection = Regex.Matches(input,
$"\{{(?<{tokenGroup}>{Regex.Escape(token)})(?<{quickFormatGroup}>{nativeFormatSpec}?)" &
$"((\|(?<{compareFormatGroup}>{complexFormatSpec}))?(?<{compareOperatorGroup}>=|!=|<>)(?<{compareValueGroup}>.*))?" &
$"(\|(?<{defaultFormatGroup}>{complexFormatSpec})(\|(?<{elseFormatGroup}>{complexFormatSpec}))?)?\}}")
根据您的简化数据,这里是处理提取的正则表达式:
\{(?>(?:"[^"]*(?:""[^"]*)*"|[^{}]+)|\{(?<n>)|\}(?<-n>))*(?(n)(?!))\}
见demo
这基本上是一个平衡的大括号正则表达式与 VB.NET 类似的字符串文字匹配正则表达式 "[^"]*(?:""[^"]*)*"
。请注意,这部分 - (?:"[^"]*(?:""[^"]*)*"|[^{}]+)
- 在查找配对大括号(带引号的字符串和非大括号)时实际上会被忽略。
使用正则表达式,我需要收集 valid 顶级标记 {...}
并忽略引用字符串中的标记边界"..."
(包括可能的 ""
)。
简化样本:
TEXT{bbbbb}TEXT{cccc|{dddd}}TEXT{eeee|ff{gg}hh|ii{jj}"kk}{|{}ll""mm{nn}"oo|{pppp}}TEXT
预计有 3 场比赛:
{bbbbb}
{cccc|{dddd}}
{eeee|ff{gg}hh|ii{jj}"kk}{|{}ll""mm{nn}"oo|{pppp}}
请注意字符串"kk}{|{}ll""mm{nn}"
的内容被忽略
每个标记都应遵循以下语法:
'{'<tokenName>[a1]['|'[a2|c1]('='|'<>')c2]['|'c3['|'c4]]'}'
其中 aX
是简单的正则表达式 ((,-?\d+(:.*)?|:.*)
),cX
可以包含匹配的 {
-}
、纯文本和字符串 "..."
其中 {
、}
、|
、""
等特殊字符被视为纯文本。
我不明白此正则表达式中需要的平衡和转义。对于初学者来说可能太难了。
其他详细信息:
我已经完成了部分解决方案,我的问题是平衡和引用。
我正在尝试创建包含在 input As String
中的扩展标记,它看起来类似于 format strings,但也允许条件评估。例如在文件名模板中使用这些标记,用户可以在批处理中配置文件名的自定义部分。令牌具有字母数字名称和格式部分(包括可选条件、真部分和假部分)。格式化部分可以在:
“本机格式”——从
String.Format()
得知,但字母数字名称而不是占位符{0}
、{1}
、{2}
、.. .
正则表达式是(,-?\d+(:.*)?|:.*)
.
示例:
,3
(转换为标准{0,3}
)
:d
(转换为标准{0:d}
)
-3:d
(转换为标准{0,-3:d}
)“复杂格式”——原生格式,
或固定文字{0}
作为字符串...{0<native format>}...
的一部分上下文化 正则表达式是:"("
& nativeFormatSpec &"|.*({0.*}.*)*)"
.
示例:
-4:d
(仅限本机格式)
prefix {0,-4:d} & once more {0} suffix
被翻译成
. . . .String.Format("prefix {0,-4:d} "&}} once" more {0} suffix", value)
现在有效令牌的完整语法是:
'{'<tokenName>[quickFormat]['|'[complexFmt1]('='|'<>')value][complexFmt2|[complexFmt3]]'}'
我的代码使用了很多命名组,但正则表达式可能太简单了:
'*** matching token names (for later use as match.Group(groupName))
Const tokenGroup As String = NameOf(tokenGroup)
Const compareFormatGroup As String = NameOf(compareFormatGroup)
Const quickFormatGroup As String = NameOf(quickFormatGroup)
Const compareOperatorGroup As String = NameOf(compareOperatorGroup)
Const compareValueGroup As String = NameOf(compareValueGroup)
Const defaultFormatGroup As String = NameOf(defaultFormatGroup)
Const elseFormatGroup As String = NameOf(elseFormatGroup)
'*** subpatterns
Const nativeFormatSpec As String = "(,-?\d+(:.*)?|:.*)"
Const complexFormatSpec As String = "(" & nativeFormatSpec & "|.*({0.*}.*)*)" 'value allowing one token {0} multiple times
Dim matches As MatchCollection = Regex.Matches(input,
$"\{{(?<{tokenGroup}>{Regex.Escape(token)})(?<{quickFormatGroup}>{nativeFormatSpec}?)" &
$"((\|(?<{compareFormatGroup}>{complexFormatSpec}))?(?<{compareOperatorGroup}>=|!=|<>)(?<{compareValueGroup}>.*))?" &
$"(\|(?<{defaultFormatGroup}>{complexFormatSpec})(\|(?<{elseFormatGroup}>{complexFormatSpec}))?)?\}}")
根据您的简化数据,这里是处理提取的正则表达式:
\{(?>(?:"[^"]*(?:""[^"]*)*"|[^{}]+)|\{(?<n>)|\}(?<-n>))*(?(n)(?!))\}
见demo
这基本上是一个平衡的大括号正则表达式与 VB.NET 类似的字符串文字匹配正则表达式 "[^"]*(?:""[^"]*)*"
。请注意,这部分 - (?:"[^"]*(?:""[^"]*)*"|[^{}]+)
- 在查找配对大括号(带引号的字符串和非大括号)时实际上会被忽略。