Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find a string starting from given index

Tags:

rust

What is the correct way how to find a substring if I need to start not from 0?

I have this code:

fn SplitFile(reader: BufReader<File>) {
  for line in reader.lines() {
    let mut l = line.unwrap();
    // l contains "06:31:53.012   index0:2015-01-06 00:00:13.084
    ...

I need to find third : and parse the date behind it. Still no idea how to do it, because find doesn't have any param like begin - see https://doc.rust-lang.org/std/string/struct.String.html#method.find.

(I know I can use regex. I have it done, but I'd like to compare the performance - whether parsing by hand might the quicker than using regex.)

like image 835
stej Avatar asked Jul 07 '15 21:07

stej


People also ask

Can we access string with index?

This process is referred to as indexing. Strings are ordered sequences of character data, 00:15 and the individual characters of a string can be accessed directly using that numerical index.

How do I find a certain index of a string?

The indexOf() method returns the position of the first occurrence of specified character(s) in a string. Tip: Use the lastIndexOf method to return the position of the last occurrence of specified character(s) in a string.

What index do strings start at?

Strings are zero-indexed: The index of a string's first character is 0 , and the index of a string's last character is the length of the string minus 1.

How do you find the starting index of a substring?

To find the index of first occurrence of a substring in a string you can use String. indexOf() function. A string, say str2 , can occur in another string, say str1 , n number of times. There could be a requirement in your Java application, that you have to find the position of the first occurrence of str2 in str1 .


2 Answers

There is a lot simpler solution to this problem in my opinion, and that is to use a .splitn() method. This method splits a string by a given pattern at most n times. For example:

let s = "ab:bc:cd:de:ef".to_string();
println!("{:?}", s.splitn(3, ':').collect::<Vec<_>>());
// ^ prints ["ab", "bc", "cd:de:ef"]

In your case, you need to split the line into 4 parts separated by ':' and take the 4th one (indexed from 0):

// assuming the line is correctly formatted
let date = l.splitn(4, ':').nth(3).unwrap();

If you don't want to use unwrap (the line might not be correctly formatted):

if let Some(date) = l.splitn(4, ':').nth(3) {
    // parse the date and time
}
like image 136
faiface Avatar answered Sep 30 '22 05:09

faiface


You are right, there doesn't appear to be any trivial way of skipping several matches when searching a string. You can do it by hand though.

fn split_file(reader: BufReader<File>) {
    for line in reader.lines() {
        let mut l = &line.as_ref().unwrap()[..]; // get a slice
        for _ in 0..3 {
            if let Some(idx) = l.find(":") {
                l = &l[idx+1..]
            } else {
                panic!("the line didn't have enough colons"); // you probably shouldn't panic
            }
        }
        // l now contains the date
        ...

Update:

As faiface points out below, you can do this a bit cleaner with splitn():

fn split_file(reader: BufReader<File>) {
    for line in reader.lines() {
        let l = line.unwrap();
        if let Some(datetime) = l.splitn(4, ':').last() {
            // datetime now contains the timestamp string
            ...
        } else {
            panic!("line doesn't contain a timestamp");
        }
    }
}

You should go upvote his answer.

like image 39
Lily Ballard Avatar answered Sep 30 '22 06:09

Lily Ballard