2015-07-07 20 views
6

Wie finde ich einen Teilstring, wenn ich nicht von 0 aus anfangen soll?Suche nach einem String ab gegebenem Index

Ich habe diesen 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 
    ... 

Ich brauche : Drittel zu finden und das Datum dahinter analysieren. Immer noch keine Idee, wie es geht, denn find hat keine param wie begin - siehe https://doc.rust-lang.org/std/string/struct.String.html#method.find.

(Ich weiß, ich Regex verwenden kann ich es getan habe, aber ich möchte die Leistung vergleichen -. Ob von Hand Parsen könnte das schneller als regex.)

+2

An welche Art von Anfangsparameter denken Sie? Wenn du meinst, "begin" ist ein Offset, dann würdest du einfach schneiden und dann 's [begin ..] finden. Find (...)' – bluss

+0

Toller Kommentar, danke. – stej

Antwort

4

Sie haben Recht, es scheint keine triviale Art zu sein, mehrere Übereinstimmungen beim Suchen einer Zeichenkette zu überspringen. Sie können es jedoch von Hand tun.

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:

Als faiface Punkte aus below, können Sie mit splitn() dies etwas sauberer tun:

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

Sie sollten upvote seine Antwort gehen.

+0

Danke, ich werde es versuchen. Kannst du mir auch sagen, wie leistungsfähig das ist? Was macht das? L = & l [idx + 1 ..]? Wird ein neuer Slice im Stapel erstellt? Kopiert es die entsprechenden Bytes? Ich frage, weil ich versuche, große Dateien zu verarbeiten, und solche zusätzlichen Arbeiten können die Leistung erheblich beeinträchtigen. – stej

+1

Slices sind Referenzen, sie stellen niemals das Kopieren dar und stellen auch keine Zuweisung ihrer eigenen dar. – bluss

+0

@stej: messen, messen, messen :) In diesem speziellen Fall kann es gut sein, dass die Grenzen 'l [idx + 1 .. ] kostet mehr als die Aufgabe selbst. Sie können überprüfen, wie ein Slice im Modul ['std :: raw '] (https://doc.rust-lang.org/std/raw/struct.Slice.html) implementiert wird: nur eine Ganzzahl und ein Zeiger. –

1

Nur das Datum und nicht auch die Zeit, oder?

let test: String = "06:31:53.012 index0:2015-01-06 00:00:13.084".into(); 

let maybe_date = test.split_whitespace() 
    .skip(1) 
    .next() 
    .and_then(|substring| substring.split(":").skip(1).next()); 

assert_eq!(maybe_date, Some("2015-01-06")); 
+0

Ich nahm an, die Zeit war Teil des Datums, das stej analysieren wollte. Zusammen repräsentieren sie einen vollständig spezifizierten Zeitstempel. –

+0

Es ist wahr, ich wollte die Zeit auch analysieren. Dieser Code sieht vielleicht gut aus für kleine Dateien und zeigt einen anderen Weg, wie ich mein Problem lösen kann. Also habe ich auch geupdated. – stej

4

Es gibt viele einfachere Lösung für dieses Problem meiner Meinung nach, und das ist eine .splitn() Methode zu verwenden. Diese Methode teilt einen String maximal n mal nach einem bestimmten Muster auf. Zum Beispiel:

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

In Ihrem Fall müssen Sie die Zeile in 4 Teile von ':' und nehmen Sie die 4. ein (indexiert von 0) getrennt aufgeteilt:

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

Wenn Sie nicht wollen, Unwrap verwenden (die Zeile ist möglicherweise nicht korrekt formatiert):

if let Some(date) = l.splitn(4, ':').nth(3) { 
    // parse the date and time 
} 
+0

Guter Anruf.Ich erinnerte mich, dass Rust sich "geteilt" hatte, aber aus irgendeinem Grund dachte ich nicht an "splitn()". Übrigens könnte es konzeptionell sauberer sein, 'l.splitn (4, ':'). Last()' anstelle von '.nth (3)' zu verwenden. –

+0

Das klingt auch gut. Die andere Lösung wurde bereits implementiert, aber ich werde wahrscheinlich einige Benchmarks einschließlich dieser Lösung machen. – stej

Verwandte Themen