【问题标题】:using regex to split equations with variables C#使用正则表达式拆分具有变量 C# 的方程
【发布时间】:2016-01-13 22:28:08
【问题描述】:

我已经为此苦苦挣扎了很长一段时间(不是正则表达式忍者),搜索 stackoverflow 并尝试了一个错误。我想我已经接近了,但仍有一些小问题需要帮助解决。

要求包括变量、指数等的给定方程在变量、常量、值等之后被正则表达式模式分割。到目前为止我所拥有的

     Regex re = new Regex(@"(\,|\(|\)|(-?\d*\.?\d+e[+-]?\d+)|\+|\-|\*|\^)");
     var tokens = re.Split(equation)

所以一个方程比如

    2.75423E-19* (var1-5)^(1.17)* (var2)^(1.86)* (var3)^(3.56)

应该解析为

     [2.75423E-19 ,*, (, var1,-,5, ), ^,(,1.17,),*....,3.56,)]

但是,指数部分也被拆分,我认为这是由于正则表达式部分:|+|-。

我尝试过的其他版本是:

    Regex re1 = new Regex(@"([\,\+\-\*\(\)\^\/\ ])"); and 
    Regex re = new Regex(@"(-?\d*\.?\d+e[+-]?\d+)|([\,\+\-\*\(\)\^\/\ ])");

两者都有缺陷。任何帮助将不胜感激。

【问题讨论】:

  • 您打算如何消除负值和作为算术运算符的负数的歧义?还是这里不需要?顺便说一句,检查[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?|[-^+*/()]|\w+ 是否与标记匹配。
  • 恕我直言,我相信你最好看看适当的解析机制。
  • @stribizhev 您应该将其发布为答案,因为它正确标记了文本。顺便说一句,在算术解析中,您通常不处理负数标记,而是将数字视为带有一元减号运算符的正数。对于 OP,如果您需要编写自定义解析器,您可能会对我的 [this answer] 感兴趣,或者如果它符合您的需要,您可以使用类似 NCalc 的东西。
  • @LucasTrzesniewski:我实际上不确定我是否应该,但既然你认为我应该,我有:)
  • @stribizhev 我有一个额外的方法可以调整 urnary 运算符。

标签: c# regex equations


【解决方案1】:

对于原始问题中发布的方程式,您可以使用

[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?|[-^+*/()]|\w+

regex demo

正则表达式匹配:

  • [0-9]*\.?[0-9]+([eE][-+]?[0-9]+)? - 浮点数
  • | - 或者...
  • [-^+*/()] - 发布的等式中存在的任何算术和逻辑运算符
  • | - 或者...
  • \w+ - 1 个或多个单词字符(字母、数字或下划线)。

对于更复杂的标记化,请考虑使用Lucas Trzesniewskicomment 建议的NCalc

C# sample code:

var line = "2.75423E-19* (var1-5)^(1.17)* (var2)^(1.86)* (var3)^(3.56)";
var matches = Regex.Matches(line, @"[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?|[-^+*/()]|\w+");
foreach (Match m in matches)
    Console.WriteLine(m.Value);

并为您更新代码以表明这里不需要Regex.Split

var result = Regex.Matches(line, @"\d+(?:[,.]\d+)*(?:e[-+]?\d+)?|[-^+*/()]|\w+", RegexOptions.IgnoreCase)
             .Cast<Match>()
             .Select(p => p.Value)
             .ToList();

此外,要匹配格式化数字,您可以使用\d+(?:[,.]\d+)* 而不是[0-9]*\.?[0-9]+\d+(,\d+)*

【讨论】:

  • 感谢您的解决方案,但我仍然不太确定它是否正确。虽然正则表达式演示表明所有正确的元素都匹配,但当我实现它并拆分表达式时,我在数组中得到了一个额外的 E-19 元素。也许这是我对正则表达式库的误解,我想我可以遍历匹配集合,但是这可能会在实现其他方程时导致无法预料的问题。
  • @Jnewson 您是否使用逐字字符串语法来传递模式? @"[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?|[-^+*/()]|\w+" - 像这样?
  • @Lucas Trzesniewski 我不得不将它添加为这样的组 @"([0-9]*\.?[0-9]+([eE][-+]?[0 -9]+)?|[-^+*/,()]|\w+)" 以使其获得输出,否则在执行拆分时得到一个空数组。
  • 我提供的正则表达式不是Regex.Split,而是Regex.Matches。当您使用(....) 包围模式的一部分时,此子匹配将在Regex.Split 期间输出到结果数组中。请参阅我提供的演示。如果要使用Regex.Split,请使用@"([0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?|[-^+*/,()]|\w+)"
  • 感谢@stribizhev,我会对此表示赞同,因为它使我找到了解决方案,但不幸的是我没有足够的声誉。
【解决方案2】:

所以我想我有一个解决方案,感谢@stribizhev 解决方案引导我使用正则表达式解决方案

            Regex re = new Regex(@"(\d+(,\d+)*(?:.\d+)?(?:[eE][-+]?[0-9]+)?|[-^+/()]|\w+)");
            tokenList = re.Split(InfixExpression).Select(t => t.Trim()).Where(t => t != "").ToList();  

当 split 给我所需的数组时。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-03
    • 1970-01-01
    • 1970-01-01
    • 2022-11-30
    • 2015-09-24
    相关资源
    最近更新 更多