Я пишу программу, которая читает файл построчно, извлекает все цифры, содержащиеся в каждой строке (игнорируя любые другие символы), интерпретирует полученные цифры в каждой строке как целое число и печатает сумму целых чисел.
Файл следующий:
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 }
Почему это происходит и что я могу сделать, чтобы решить эту проблему?
То, как вы обрабатываете каждую строку по две цифры за раз, похоже, вызывает проблемы для строк 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/…
Обратите внимание: пока вы редактировали свой вопрос, я сделал код еще проще, ссылка в моем предыдущем комментарии была обновлена. :)
Сегодня я узнал.
Я не думаю, что здесь это имеет значение (я знаю, над чем работает OP, и входные данные всегда ASCII), но обычно, если цель состоит в том, чтобы проанализировать число, вам следует использовать is_ascii_digit для фильтрации, потому что is_numeric
соответствует не -Глифы ASCII Unicode, относящиеся к числовой категории, которые parse
будут задушены.
И вот версия, которая позволяет избежать промежуточного String
выделения и синтаксического анализа.
Если вы измените строку отладки для использования вывода отладки ({:?}
):
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();
В программе все еще могут быть другие ошибки, из-за которых ее вывод неверен, но это исправляет конкретную ошибку, которую вы видите.
Совет: не используйте контрольные значения, такие как
'\0'
, для обозначения пропущенных значений, используйтеOption::None
. Тогда вы не столкнетесь с такими проблемами.