2016-12-25 4 views
2

коротковатой версияRegex для разбора плохо отформатированных полиномов

Я использую это регулярное выражение:

(^|[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^ считается «неправильным», но 4x2 и 4x^2 оба хороши?

Т.Л., др версия

Я пытаюсь синтаксического анализа полиномиальных уравнений, введенные пользователем для того, чтобы подтвердить, а затем разложить уравнение в ряд элементов. Уравнения будут представлены как строки.

Вот пример того, как пользователи просят форматировать их строку:

y = 2.0x^2.5 - 3.1x + 5.2 

Где x является независимой переменной (не символ раза) и y является зависимой переменной.

В действительности пользователи обычно делают любой из следующих ошибок:

  • Забыв включить y =
  • Добавление * к коэффициентам, таких как y = 2.0*x
  • Использование целых чисел вместо поплавков, например y = 5x
  • Отсутствует ^ при настройке порядка, например. y = x3
  • Добавление или удаление пробелов в любом месте

Однако для всех из них, я бы сказал, что это все-таки легко понять, что пользователь пытается писать. Под этим я подразумеваю, что очевидно, что коэффициент и порядок предназначены для каждого элемента.

Так что я хочу написать некоторое регулярное выражение, которое правильно разделяет введенную строку на отдельные элементы и может получить мне A (коэффициент) и B (порядок) каждого элемента, где элемент вообще имеет форму Ax^B и A и B могут быть любыми действительными числами.

я придумал следующий пример:

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.

Благодарим за помощь.

p.s. Программа должна быть написана в Go, но я тоже немного нуб в Go, поэтому я первый прототип в Python. Не уверен, что это будет иметь какое-то значение для регулярного выражения (я действительно новичок в регулярном выражении).

+0

Я просто хочу отметить, что '{0,}' может быть '*' и '{0,1}' is '?'. – Uriel

+0

Я думаю, что ответ, который вы пытаетесь получить, это ((1.0, 1.0), (3.3, -50.0), (15.0, 25.5), (2.0, 2.0), (3.0, -2.5), (1.1, 0.0)) ... обратите внимание, что пятая пара (3.0, -2.5) вместо (3.0, -3.5). Правильно? –

ответ

0

следующее регулярное выражение будет в основном делать:

(?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 попробовать.

+0

Большое вам спасибо, это был небольшой проект, над которым я работал над xmas и просто решил вернуться - очень ценю помощь! – Chris

Смежные вопросы