«десятичный литерал пустой» при объединении нескольких строк для регулярного выражения в Rust - PullRequest
0 голосов
/ 27 декабря 2018

Я хочу разобрать строку для создания вектора чисел с плавающей запятой:

fn main() {
    let vector_string: &str = "{12.34, 13.}";
    let vec = parse_axis_values(vector_string);
    // --- expected output vec: Vec<f32> = vec![12.34, 13.]
}

use regex::Regex;

pub fn parse_axis_values(str_values: &str) -> Vec<f32> {
    let pattern_float = String::from(r"\s*(\d*.*\d*)\s*");
    let pattern_opening = String::from(r"\s*{{");
    let pattern_closing = String::from(r"}}\s*");
    let pattern =
        pattern_opening + "(" + &pattern_float + ",)*" + &pattern_float + &pattern_closing;
    let re = Regex::new(&pattern).unwrap();
    let mut vec_axis1: Vec<f32> = Vec::new();
    // --- snip : for loop for adding the elements to the vector ---

    vec_axis1
}

Этот код компилируется, но при развертывании Regex::new():

regex parse error:
    \s*{{(\s*(\d*.*\d*)\s*,)*\s*(\d*.*\d*)\s*}}\s*
        ^
error: decimal literal empty
* возникает ошибка во время выполнения1007 * Согласно другим сообщениям, эта ошибка может возникать, когда экранирование фигурной скобки { не выполняется должным образом, но я думаю, что я избежал скобки правильно.

Что не так с этим регулярным выражением?

1 Ответ

0 голосов
/ 27 декабря 2018

В вашем коде есть несколько проблем:

  1. Экранирование { в регулярном выражении выполняется с помощью \{.

  2. Ваш . соответствует любому персонажу и не берет то, что вы хотите.Вы должны избежать этого.

  3. Вы захватываете больше, чем просто число, что делает анализ более сложным.

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

Вот предлагаемая улучшенная версия:

use regex::Regex;

pub fn parse_axis_values(str_values: &str) -> Vec<f32> {
    let re = Regex::new(r"(?x)
        \s*\{\s*        # opening
        (\d*\.\d*)      # captured float
        \s*,\s*         # separator
        \d*\.\d*        # ignored float
        \s*\}\s*        # closing
    ").unwrap();
    let mut vec_axis1: Vec<f32> = Vec::new();
    if let Some(c) = re.captures(str_values) {
        if let Some(g) = c.get(1) {
            vec_axis1.push(g.as_str().parse().unwrap());
        }
    }
    vec_axis1
}

fn main() {
    let vector_string: &str = "{12.34, 13.}";
    let vec = parse_axis_values(vector_string);
    println!("v: {:?}", vec);
}

детская площадка

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

Я хочу иметь возможность сопоставлять 0.123, .123, 123 или 123., использование d+ нарушит эти возможности

Похоже, вы хотите получить все поплавки в строке.Это можно сделать просто так:

use regex::Regex;

pub fn parse_axis_values(str_values: &str) -> Vec<f32> {
    let re = Regex::new(r"\d*\.\d*").unwrap();
    let mut vec_axis1: Vec<f32> = Vec::new();
    for c in re.captures_iter(str_values) {
        vec_axis1.push(c[0].parse().unwrap());
    }
    vec_axis1
}

Если вы хотите, чтобы оба:

  • , чтобы убедиться, что вся строка правильно заключена между { и }
  • для захвата всех чисел

Тогда вы можете либо:

  • объединить два регулярных выражения (первое используется для извлечения внутренней части)
  • использовать анализатор на основе Serde (я бы не стал, но было бы интересно, если бы сложность проблемы возрастала)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...