Разбор инфиксных математических выражений в Swift с использованием регулярных выражений - PullRequest
0 голосов
/ 05 марта 2019

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

Например:

"31+2--3*43.8/1%(1*2)" -> ["31", "+", "2", "-", "-3", "*", "43.8", "/", "1", "%", "(", "*", "2", ")"]

Я уже реализовал метод, который выполняет эту задачу, однако он состоит из множества строк кода и нескольких вложенных циклов .Я подумал, что когда я определю больше операторов / функций, которые могут даже состоять из нескольких символов, таких как log или cos, будет проще редактировать строку регулярного выражения, чем добавлять еще много строк кода в мою рабочую функцию.Подходят ли регулярные выражения для этого, и если да, то где я иду не так?Или мне лучше добавить в мой рабочий парсер?

Я уже ссылался на следующие сообщения SO:

Как разбить строку, но также сохранить разделители?

Это было очень полезно, но я не думаю, что я правильно использую 'lookahead'.

Проверка математических выражений с использованием регулярных выражений?

Решение вышеуказанного вопроса не преобразует строку в массив токенов.Скорее, он проверяет, является ли данная строка допустимым математическим выражением.

Мой код выглядит следующим образом:

func convertToInfixTokens(expression: String) -> [String]?
{
    do
    {
        let pattern = "^(((?=[+-/*]))(-)?\\d+(\\.\\d+)?)*"

        let regex = try NSRegularExpression(pattern: pattern)

        let results = regex.matches(in: expression, range: NSRange(expression.startIndex..., in: expression))

        return results.map
        {
            String(expression[Range($0.range, in: expression)!])
        }
    }
    catch
    {
        return nil
    }
}

Когда я передаю действительное выражение инфикса этой функции, оновозвращает nil.Где я ошибаюсь с моей строкой регулярных выражений?

ПРИМЕЧАНИЕ: Я даже не пытался разобрать скобки как отдельные токены.Я все еще выясняю, почему это выражение не сработает:

"-99+44+2+-3/3.2-6"

Любая обратная связь приветствуется, спасибо!

1 Ответ

0 голосов
/ 05 марта 2019

Ваш шаблон не работает, потому что он совпадает только с текстом в начале строки (см. ^ якорь), тогда положительный прогноз (?=[+-/*]) требует, чтобы первый символ был оператором из указанного набора, но единственным операторомто, что вы потребляете, является необязательным -.Таким образом, когда * пытается сопоставить вложенную последовательность шаблонов во второй раз с -99+44+2+-3/3.2-6, он видит +44, а -?\d не может сопоставить его (так как он не знает, как сопоставить + с -?).

Вот как ваше регулярное выражение соответствует строке:

enter image description here

Вы можете токенизировать выражение, используя

let pattern = "(?<!\\d)-?\\d+(?:\\.\\d+)?|[-+*/%()]"

См. Демонстрационный пример regex

Подробности

  • (?<!\d) - слева от знака не должно быть цифртекущая позиция
  • -? - необязательно -
  • \d+ - 1 или более цифр
  • (?:\.\d+)? - необязательная последовательность . и 1+ цифры
  • | - или
  • \D - любой символ, кроме цифры.

Вывод с использованием вашей функции:

Optional(["31", "+", "2", "-", "-3", "*", "43.8", "/", "1", "%", "(", "1", "*", "2", ")"])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...