我想接受用户输入的一系列模式的主要增量,以次要增量的流体。1gal-1qt-2pt-2cup-5oz
我需要强制执行单位后缀的顺序(gal->qt->pt->cup->oz),但是任何特定的增量都是可选的,以允许用户获得最大的表现力,例如
1gal-6oz
是有效输入1gal
有效6oz
有效
我打算提取数值作为捕获组。
我问了一个类似的问题here,这很有帮助,但最终我很难把这个问题应用到这个问题上。
我面临的挑战是:
1.分隔符的可见性,它需要根据前面元素的存在而出现或消失。
1.当模式的大部分对于一个有效的匹配不是必需的,而不是必须有至少一个numeral+suffix
匹配时的“可选性”。
也许正则表达式并不是最好的表示方法,我应该看看解析尝试,或类似的。
我怎么能做到这一点?
编辑:
我用第四只鸟的回复和LogiKals的回复运行了一些C#基准测试。首先,我运行基准测试6个模式,内存开销是相同的31 kb。Logikal在0.5ns时出现,而T4 B在0.66ns时出现。
然后,我将测试提高到1000次迭代,T4 B在速度上领先,但并没有太多。对于1000次运行,内存开销在mb范围内。
我不知道如何使用正则表达式来选择其中任何一个作为“最佳答案”,所以如果有人能给我建议,我将不胜感激。他们两个都非常有帮助。谢谢.
6条答案
按热度按时间s2j5cfk01#
这里有一个基于正则表达式的解决方案。
我的正则表达式应该是这样的:
将其写入多行以提高可读性:
正则表达式基于以下模式构建:
(?=^\d+[a-z]+(?:-\d+[a-z]+)*$)
(?:(?<gal>\d+)gal(?=-|$))?-?
第一种是确保尊重一般模式。
第二个匹配单个值,数字为named capturing group。它确保模式以连字符或字符串结尾结束,并允许在结尾插入可选的连字符。
请参阅here的演示。
如果你愿意,你可以用单词边界(
\b
)替换(?=-|$)
。对于.NET表达式,命名组称为命名匹配子表达式。
zyfwsgd62#
另一个想法是使用word-boundaries和optional分组/连字符:
See this demo at regex101
-
的位置或以单词字符开始/结束。也要求至少有一个项目(不允许空字符串)。ut6juiuv3#
另一种选择是首先声明整个字符串的格式,然后使所有部分都是可选的。
在C#中,你可以使用atomic groups
(?>
来防止一些不必要的回溯。模式匹配:
^
字符串开头(?=\d+[a-z]+(?:-\d+[a-z]+)*$)
正向先行,Assert字符串的格式,因此也至少出现一次(?>(?<gal>\d+)gal-?)?
原子组,可选匹配组gal中的1+位,后跟文本“gal”和可选连字符(?>(?<qt>\d)+qt-?)?
qt的组(?>(?<pt>\d+)pt-?)?
pt的组(?>(?<cup>\d+)cup-?)?
cup组(?>(?<oz>\d+)oz-?)?
oz组$
字符串结尾参见Regex demo和C# demo。
oxosxuxt4#
对于任何给定的字符串:
问题所举的例子显示有较严格的规定,但我选择从较一般和字面的Angular 来解释问题。例如,下面的字符串满足上述要求。
当且仅当字符串与以下正则表达式匹配时,字符串才满足这些要求:
我在正则表达式中使用了缓和贪婪标记技术。要了解这是如何工作的,请考虑regex
它一次匹配一个字符,只有当它不包含任何字符串
"gal"
,"qt"
,"pt"
,"cup"
或"oz"
,前面是一个数字或一个词边界(\b
),后面是一个词边界时,它才会匹配字符串。由于单词边界,它将匹配字符串(例如)“3 cupcakes”。正则表达式具有以下元素。
yfjy0ee75#
您可以使用以下方法:
1.将输入字符串拆分到
-
上(正如@Barmar在他们对问题帖子的评论中所建议的那样)1.然后,对于拆分输入字符串的每个部分:
1.使用正则表达式验证部件是否以整数开头
1.验证部分是否以有效单位结束(紧跟在整数之后)
1.验证单位“size”是否小于前一个单位“size”
要检查部分是否以有效单位结尾(步骤2.2),可以使用正则表达式删除初始整数部分,然后尝试在仅包含有效单位的字典中查找单位。(由于步骤2.3,我建议使用字典而不是哈希集。
要检查单位“size”是否小于前面的单位“size”(步骤2.3),包含有效单位的字典可以将“comparison size”作为单位(键)的值。例如,物理单位越大,“比较大小”就越大(
"gal": 4
,"qt": 3
,等等)。这一办法的一种实施方式可以是:
wgxvkvu96#
如果你想要“一个非空的字符串
^(?!$)
,有顺序的可选单位,其中单位是一个数字%n
,单位名称,如果不在最后则减去%d
“它看起来像https://regex101.com/r/RfCKYO/1
(我使用https://tsplay.dev/dimava-regex101-markup-1 js片段在regex101上使用此标记)