【问题标题】:Regex to parse badly formatted polynomials正则表达式解析格式错误的多项式
【发布时间】:2017-05-10 02:58:36
【问题描述】:

短版

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

(^|[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 版本

我正在尝试解析用户输入的多项式方程,以验证该方程并将其分解为一系列元素。方程将显示为字符串。

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

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 不显示为y = 2x^2

感谢您的帮助。

附言用 Go 编写的程序,但我在 Go 方面也有点菜鸟,所以我第一次用 Python 进行原型设计。不确定这是否会对正则表达式产生任何影响(我真的是正则表达式的新手)。

【问题讨论】:

  • 我会注意到{0,} 可以是*{0,1}?
  • 我认为您想要得到的答案是 ((1.0, 1.0), (3.3, -50.0), (15.0, 25.5), (2.0, 2.0), (3.0, -2.5) , (1.1, 0.0))... 注意第 5 对是 (3.0,-2.5) 而不是 (3.0,-3.5)。对吗?

标签: python regex go


【解决方案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试试。

【讨论】:

  • 非常感谢,这是我圣诞节期间正在做的一个小项目,我决定回来 - 非常感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-24
  • 2021-07-18
  • 1970-01-01
  • 1970-01-01
  • 2012-10-17
  • 1970-01-01
相关资源
最近更新 更多