正则表达式解析格式错误的多项式

时间:2016-12-25 00:06:06

标签: python regex go

简短版

我正在使用这个正则表达式:

(^|[yY]\s{0,}\=|\+|\-)\s{0,}([0-9]{0,}\.?[0-9]{0,})\s{0,}(\*{0,1}[xX]{0,1})\s{0,}(\^{0,1})(-?)([0-9]{0,}\.?[0-9]{0,})(\s{0,}|$)?

尝试从以下公式中提取所有元素系数和订单号:

y=x+3.3X^-50+ 15x25.5 - 4x^+2x^2 +3*x-2.5+1.1

我希望正则表达式忽略错误的4x^,它错过了它的电源号码(目前没有这样做)并允许我达到这个最终结果:

((1.0, 1.0), (3.3, -50.0), (15.0, 25.5), (2.0, 2.0), (3.0, -3.5), (1.1, 0.0))

其中第一个坐标是系数,第二个坐标是每个元素的顺序。目前上面的正则表达式几乎是'如果我采用第1组和第2组以及第5组和第6组分别给出系数和顺序,则可以正常工作。

它只是落在了错误的4x^加上感觉非常不优雅,但我在正则表达式上有些不高兴,并且不确定要做出哪些改进。

如何改进此正则表达式,并进行修正,以便4x^被视为错误'但是4x24x^2都很好吗?

tl; dr version

我正在尝试用户输入的解析多项式方程,以便验证然后将方程式分解为一系列元素。方程将以字符串形式呈现。

以下是如何要求用户格式化其字符串的示例:

y = 2.0x^2.5 - 3.1x + 5.2

其中x是自变量(不是时间符号),y是因变量。

实际上,用户通常会犯以下错误:

  • 忘记加入y =
  • *添加到y = 2.0*x
  • 等系数
  • 使用整数而不是浮点数,例如y = 5x
  • 设置订单时遗漏^,例如y = x3
  • 在任何地方添加或删除空格

然而,对于所有这些,我说它仍然很容易理解用户试图写什么。我的意思是,显然每个元素的系数和顺序是什么。

所以我想做的是写一些正则表达式,正确地将输入的字符串拆分成单独的元素,并且可以得到每个元素的A(系数)和B(顺序)一般来说,元素的格式为Ax^BAB可以是任何实数。

我设计了以下示例:

y=x+3.3X^-50+ 15x25.5 - 4x^+2x^2 +3*x-2.5+1.1

我相信其中涵盖了我上面列出的所有潜在问题,另外还有一个直接错误4x^+2x^2错过了元素4x^上的顺序。

对于此示例,我想访问:((1.0, 1.0), (3.3, -50.0), (15.0, 25.5), (2.0, 2.0), (3.0, -3.5), (1.1, 0.0))其中4x^被忽略。

我对regex有点新,但我已经努力使用regex101.com来创建以下内容:

(^|[yY]\s{0,}\=|\+|\-)\s{0,}([0-9]{0,}\.?[0-9]{0,})\s{0,}(\*{0,1}[xX]{0,1})\s{0,}(\^{0,1})(-?)([0-9]{0,}\.?[0-9]{0,})(\s{0,}|$)?

这看起来几乎有效,存在以下问题:

  • 根据上面给出的示例4x^,没有捕获缺失的订单 - 我不确定如何使订单号的可选性'有条件的'如果^不存在,但订单号如^
  • 感觉非常简洁/不优雅,但缺乏经验我很难看到可以改进的地方

另请注意我很高兴地忽略了重复元素的问题,其中相同的顺序没有被总结,例如我很高兴忽略y = 4x2没有显示为y = x^2 + x^2

感谢您的帮助。

P.S。要用Go编写的程序,但我在Go中也是一些菜鸟,所以我首先在Python中进行原型设计。不确定这是否会对正则表达式产生任何影响(我真的是正则表达式的新手)。

1 个答案:

答案 0 :(得分:1)

以下正则表达式主要是:

(?P<c1>[+-]? *\d+(?:\.\d+)?)? *\*? *[xX] *(?:\^ *(?P<e1>-? *\d+(?:\.\d+)?)|(?P<e2>-? *\d+(?:\.\d+)?)?)|(?P<c2>[+-]? *\d+(?:\.\d+)?)

我主要是因为这个解决方案将“4x ^”情况视为具有顺序1,因为要求已经非常宽松,否则试图忽略这样的术语会使RE变得更加复杂甚至不可能,因为它会产生模糊性无法使用RE进行解析。

请注意,缺少的系数/指数不会被捕获为您在示例结果中表示的“1.0”,这必须在应用正则表达式并将所有空捕获组作为“1”(或“0”)后完成'对于指数取决于捕获的组)。

Here you have the regex in regex101.com用于检查/尝试其工作原理。

这是golang的一个工作程序,用于测试几个案例:

package main

import (
    "fmt"
    "regexp"
    "strconv"
    "strings"
)

const e = `(?P<c1>[+-]? *\d+(?:\.\d+)?)? *\*? *[xX] *(?:\^ *(?P<e1>-? *\d+(?:\.\d+)?)|(?P<e2>-? *\d+(?:\.\d+)?)?)|(?P<c2>[+-]? *\d+(?:\.\d+)?)`

var cases = []string{
    "y=x+3.3X^-50+ 15x25.5 - 4x^+2x^2 +3*x-2.5+1.1",
    "3.3X^-50",
}

func parse(d float64, ss ...string) float64 {
    for _, s := range ss {
        if s != "" {
            c, _ := strconv.ParseFloat(strings.Replace(s, " ", "", -1), 64)
            return c
        }
    }
    return d
}

func main() {
    re := regexp.MustCompile(e)
    for i, c := range cases {
        fmt.Printf("testing case %v: %q\n", i, c)
        ms := re.FindAllStringSubmatch(c, -1)
        if ms == nil {
            fmt.Println("no match")
            continue
        }
        for i, m := range ms {
            fmt.Printf("  match %v: %q\n", i, m[0])
            c := parse(1.0, m[1], m[4])
            de := 1.0
            if m[4] != "" {
                de = 0.0
            }
            e := parse(de, m[2], m[3])
            fmt.Printf("    c: %v\n", c)
            fmt.Printf("    e: %v\n", e)
        }
    }
}

哪个输出:

testing case 0: "y=x+3.3X^-50+ 15x25.5 - 4x^+2x^2 +3*x-2.5+1.1"
  match 0: "x"
    c: 1
    e: 1
  match 1: "+3.3X^-50"
    c: 3.3
    e: -50
  match 2: "+ 15x25.5"
    c: 15
    e: 25.5
  match 3: "- 4x"
    c: -4
    e: 1
  match 4: "+2x^2"
    c: 2
    e: 2
  match 5: "+3*x-2.5"
    c: 3
    e: -2.5
  match 6: "+1.1"
    c: 1.1
    e: 0
testing case 1: "3.3X^-50"
  match 0: "3.3X^-50"
    c: 3.3
    e: -50

Here you have the program on golang playground尝试。