Почему я получаю `ParseIntError { kind: InvalidDigit }` при анализе того, что кажется допустимой целочисленной строкой?

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

Файл следующий:

1abc2
pqr3stu8vwx
a1b2c3d4e5f
treb7uchet

Ожидаемый результат: 12 + 38 + 12345 + 7 = 12402.

Это моя попытка:

use std::fs;

fn main() {
    let contents = fs::read_to_string("day1.txt").expect("Should have been able to read the file");
    const ARRAY_REPEAT_VALUE: String = String::new();
    let mut number_array: [String; 4] = [ARRAY_REPEAT_VALUE; 4];
    let mut counter: usize = 0;

    for i in contents.lines() {
        let mut on_to_next: bool = false;
        let mut num1: char = '\0';
        let mut num2: char = '\0';
        for j in i.chars() {
            if j.is_numeric() {
                if on_to_next {
                    num2 = j;
                } else {
                    num1 = j;
                    on_to_next = true;
                }
            }
        }
        number_array[counter] = format!("{}{}", num1, num2);
        counter += 1;
    }

    let mut total: i32 = 0;
    for p in number_array {
        print!("-{}-\n", p.trim());
        let converted_number: i32 = p.trim().parse().unwrap();
        total += converted_number;
    }
    print!("{}", total);
}

Но это терпит неудачу:

thread 'main' panicked at src/main.rs:35:54:
called `Result::unwrap()` on an `Err` value: ParseIntError { kind: InvalidDigit }

Почему это происходит и что я могу сделать, чтобы решить эту проблему?

Совет: не используйте контрольные значения, такие как '\0', для обозначения пропущенных значений, используйте Option::None. Тогда вы не столкнетесь с такими проблемами.

cafce25 20.08.2024 08:10
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
2
1
66
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

То, как вы обрабатываете каждую строку по две цифры за раз, похоже, вызывает проблемы для строк a1b2c3d4e5f и treb7uchet.

Вместо этого, как насчет использования более функционального подхода:

use std::fs;

fn main() {
    let contents = fs::read_to_string("src/day1.txt").expect("Failed to read the file");
    let total: i32 = contents
        .lines()
        .filter_map(|line| {
            line.chars()
                .filter(|c| c.is_numeric())
                .collect::<String>()
                .parse::<i32>()
                .ok()
        })
        .sum();
    println!("Total sum: {}", total);
}

Выход:

Total sum: 12402

Если вы готовы отказаться от предупреждения «не удалось проанализировать», вы можете упростить это еще больше. play.rust-lang.org/…

cdhowie 20.08.2024 02:36

Обратите внимание: пока вы редактировали свой вопрос, я сделал код еще проще, ссылка в моем предыдущем комментарии была обновлена. :)

cdhowie 20.08.2024 02:39

Сегодня я узнал.

Sash Sinha 20.08.2024 02:41

Я не думаю, что здесь это имеет значение (я знаю, над чем работает OP, и входные данные всегда ASCII), но обычно, если цель состоит в том, чтобы проанализировать число, вам следует использовать is_ascii_digit для фильтрации, потому что is_numeric соответствует не -Глифы ASCII Unicode, относящиеся к числовой категории, которые parse будут задушены.

cdhowie 20.08.2024 02:43

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

eggyal 20.08.2024 07:08
Ответ принят как подходящий

Если вы измените строку отладки для использования вывода отладки ({:?}):

print!("-{:?}-\n", p.trim());

Вы заметите, что последний фрагмент строки, который вы пытаетесь проанализировать, содержит нулевой символ:

-"12"-
-"38"-
-"15"-
-"7\0"-

Ваш .trim() здесь совершенно ничего не делает; вместо этого вы можете использовать .trim_end_matches('\0'), чтобы исправить непосредственную ошибку:

let converted_number: i32 = p.trim_end_matches('\0').parse().unwrap();

В программе все еще могут быть другие ошибки, из-за которых ее вывод неверен, но это исправляет конкретную ошибку, которую вы видите.

Другие вопросы по теме