Help me. reading file and extract content

// Purpose: read field from a file.txt and extract content

/* content of info.txt:
Original Title
    Paradise Highway 
Year
    2022
Country
    United States
*/
use std::{
    fs::File,
    io::{BufRead, BufReader, Seek, SeekFrom},
};
use std::fs;
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() {
    // info.txt root
    let filename = "/Book/info.txt"; 
    
    // variables to store result
    let mut original_title: &str = "";
    let mut _year = String::new();
    
    // open file
    let reader = fs::read_to_string(filename)
                    .expect("Except: file info.txt !!!");
    
    let info_txt=reader.split("\n");    
    for line in info_txt {
        if line.contains("Original Title") {
            original_title = find(&reader, &line);
        }
    } // end for line
    println!("Original title is -> {}", original_title); // print empty
    
}

Format your code, please. Make it look nice and welcome for people trying to help you.

3 Likes

Also, there's no question. Don't make us guess what the problem is.

2 Likes

tell me now. please

I'm quite sure this is supposed to be found, not !found.

on the next iteration, read the newline. under the field.

Here a minimal example:

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
}

Playground.

Stdout:

Original title is ->     Paradise Highway 
2 Likes

Great!, very educational.

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 !!!");

Jofas, what's happening to me ?

convert type ?

Your error probably originates in this line:

original_title = find(&reader, &line).unwrap();

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.

the type of variables is:

let info_txt=reader.split("\n"); ---> core::str::iter::Split<&str>
let reader: &str = "...."; ---> &str

and the file root is ok:
/home/pichibw/info.txt

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();
    }
}
2 Likes

Thank you Windows for \r\n jajaja
Great, Jofas. :hugs:

how would it be using match ??

You mean like

match line {
    _ if line.contains("Original Title") => { ... },
    _ if line.contains("AKA") => { ... },
    _ => { ... }
}

?

1 Like

what is more efficient ? if or match ?

Almost surely no difference, but if there is one it will be dwarfed by the surrounding IO and allocation, so don't worry about it.

3 Likes