fn find<'a>(input: &'a str, key: &str) -> Option<&'a str> {
let mut found = false;
for line in input.lines() {
// ... you know you return the line AFTER the line where you found `key`, right?
if found {
return Some(line);
} else if line.contains(key) {
found = true;
}
}
None
}
fn main() {
// variables to store result
let mut original_title: &str = "";
let reader = "\
Original Title
Paradise Highway
Year
2022
Country
United States";
let info_txt = reader.split("\n");
for line in info_txt {
if line.contains("Original Title") {
original_title = find(&reader, &line).unwrap();
}
} // end for line
println!("Original title is -> {}", original_title); // print empty
}
ERROR OUTPUT:
thread 'main' panicked at 'called Option::unwrap() on a None value', src/main.rs:92:51
note: run with RUST_BACKTRACE=1 environment variable to display a backtrace
when i use:
let reader = fs::read_to_string(filename)
.expect("Except: file info.txt !!!");
If you can't find your key (&line), None is returned by your function, because we didn't find what we are searching for (the "Original Title"). That probably means that the file /Book/info.txt does not contain a line with "Original Title" in it.
I think the problem is the content of /home/pichibw/info.txt. Your find function seems (to me) unable to locate "Original Title" in any of the lines of your file.
when print content of variable:
let info_txt=reader.split("\n");
println!("type of info_txt: {}", type_of(&info_txt)); // function to obtain the type
println!("Content of info.txt: {:?}", info_txt); // print content
OUTPUT:
type of info_txt: core::str::iter::Split<&str>
Content of info.txt: Split(SplitInternal { start: 0, end: 1361, matcher: StrSearcher { haystack: "\u{feff}\r\nOriginal Title\r\n Plane\r\nAKA\r\n The Plane\r\nYear\r\n ... etc etc
Thank you Windows for \r\n. Inside find we use .lines() to iterate over lines. In your main we use .split("\n"). What happens is that we search for "Original Title\r" as key, because splitting at \n won't remove the trailing \r from each line. .lines() removes the trailing \r from each line, which is why we never find a match. Replace the .split("\n") with .lines() in your main and it'll work:
for line in reader.lines() {
if line.contains("Original Title") {
original_title = find(&reader, &line).unwrap();
}
}
If you want to work on the efficiency of your program, you should make your algorithm more efficient. It does a lot of needless iterations you can avoid.
Given the structure of your input (field name in one line followed by its value in the next line), we can extract all the fields in one single pass over your input, reducing the time complexity from O(lines * log(lines)) to O(lines):
fn main() {
let mut original_title: &str = "";
let mut year: &str = "";
let mut country: &str = "";
let reader = "\
Original Title
Paradise Highway
Year
2022
Country
United States";
let mut lines = reader.lines();
while let (Some(key), Some(value)) = (lines.next(), lines.next()) {
if key.contains("Original Title") {
original_title = value;
} else if key.contains("Year") {
year = value;
} else if key.contains("Country") {
country = value;
}
}
println!("Original title is -> {}", original_title);
println!("Year is -> {}", year);
println!("Country is -> {}", country);
}
Here an example that uses something closer to your input. Your files start with a line containing the special unicode character \u{feff}. We have to skip this line or else our algorithm is off, having keys in the position of values and values in the position of keys when we try and parse the input as lines. So all we got to do is skip reading the first line:
fn main() {
let mut original_title: &str = "";
let mut year: &str = "";
let mut country: &str = "";
let reader = "\u{feff}\r\nOriginal Title\r\n Plane\r\nAKA\r\n The Plane\r\nYear\r\n 2022\r\nCountry\r\n United States\r\n";
let mut lines = reader.lines();
// skip first line "\u{feff}"
lines.next();
while let (Some(key), Some(value)) = (lines.next(), lines.next()) {
if key.contains("Original Title") {
original_title = value;
} else if key.contains("Year") {
year = value;
} else if key.contains("Country") {
country = value;
}
}
println!("Original title is -> {}", original_title);
println!("Year is -> {}", year);
println!("Country is -> {}", country);
}
As side note, AFAICT, \u{feff} is the byte order mark for UTF-16, not UTF-8 which is the encoding Rust strings use. If your files are UTF-16 encoded and contain non-ASCII charakters, parsing your files as UTF-8 can fail in funny ways. I'm not too well read on unicode encodings, I just remember having to debug why my strings in Dart were looking funny when they came from my json API (Dart strings are UTF-16 and json is UTF-8 encoded).