2017-10-24 5 views
1

ich eine Datei haben, die Abschnitte wie diese hat,mehrzeilige Datei grep

flags...id, description, used, color 
AB, "Abandoned", 0, 13168840 
DM, "Demolished", 0, 15780518 
OP, "Operational", 0, 15780518... 

wo ... z.B. eine Reihe von Steuerzeichen darstellt, ETX und STX. Ich versuche, mehrere Zeilen aus der Datei zu greifen.

Ich verwende den folgenden Code ein:

f = File.open(somePath) 
r = f.grep(/flags.+id, description, used, color(?<data>(?:.|\s)*?)[\x00-\x08]/) 

Dieser Code funktioniert nicht. Ich verstehe nicht warum. Die Dokumentation von Grep scheint anzudeuten, dass die Datei zeilenweise analysiert wird. Ich habe das Gefühl, dass dies der Grund dafür ist, dass der reguläre Ausdruck keine Ergebnisse liefert.

  1. Bin ich richtig, dass Grep Zeilen-Parsing verwendet? Aus diesem Grund funktioniert meine Regex nicht wie beabsichtigt?
  2. Wäre es besser, file.each_line zu verwenden, um die Daten zu erfassen?
  3. Gibt es bessere/sauberere Alternativen zu allen oben genannten?
+0

Sie haben nicht die Zeit entkam '.'. Sie müssen '\ .' schreiben. – sawa

+0

@sawa, bist du sicher? Sancam sagt "wo ... steht für eine Reihe von Steuerzeichen". Er denkt nicht nach Perioden, denke ich. –

+0

@Philicare Ich sehe. Du hast recht. – sawa

Antwort

1

String#scan kommt zur Rettung:

File.read('/path/to/file').scan(
    /flags.+id, description, used, color(?<data>(?:.|\s)*?)[\x00-\x08]/m 
) 
+0

Es scheint, dass das Problem tatsächlich ist, dass ich eine Binärdatei lesen, scheint es. Ich kann 'File.binread (" C: \\ Benutzer \\ jwa \\ Desktop \\ TBD \\ master.db ")' verwenden, um sicherzustellen, dass ich die ganze Datei bekomme, aber trotzdem scheint die Regex nicht zu funktionieren. .. Seltsamerweise gibt sogar das Suchen nach '/./' keine Ergebnisse zurück ... Das ist also verwirrend ... xD Edit: Hoppla, mein Fehler '/./' gibt Matches zurück. – Sancarn

+0

Denke daran, den Dateiinhalt zu teilen? Ich glaube, explizite 'File.binread() .force_encoding (Encoding :: BINARY)' könnte helfen. – mudasobwa

+0

Sicher https://ufile.io/rsakp. Ich habe auch versucht, 'enforce_encoding' zu verwenden, aber es scheint, als wäre es keine Methode in meiner alten Version von ruby ​​(1.9.1). – Sancarn

0

Sie müssen den Mehrzeilenmodus aktivieren. . stimmt standardmäßig nicht mit Zeilenvorschüben überein.

Aus der Dokumentation https://ruby-doc.org/core-2.1.1/Regexp.html

/./ - Any character except a newline. 
/./m - Any character (the m modifier enables multiline mode) 
+0

aber \ s stimmt standardmäßig mit neuen Zeilen überein. Ich denke nicht, dass das relevant ist. 'm' bedeutet, soweit ich weiß, dass jede Zeile als eigener Heuhaufen behandelt wird, so dass'^'der Anfang der Zeile ist und' $ 'das Ende der Zeile ist. – Sancarn

0

Bin ich richtig, dass grep verwendet line-by-line-Analyse?

Ja. Versuchen Sie, auf Ihrer Datei:

r = File.open(somePath) do |f| 
    f.grep(/[A-Z]{2},/) 
end 

puts r 
# => AB, "Abandoned", 0, 13168840 
# DM, "Demolished", 0, 15780518 
# OP, "Operational", 0, 15780518 

puts r.inspect 
# => ["AB, \"Abandoned\", 0, 13168840\n", "DM, \"Demolished\", 0, 15780518\n", "OP, \"Operational\", 0, 15780518\n"] 

Ist das, warum mein regex ist nicht wie beabsichtigt?

Nicht nur. Wonach suchen Sie mit [\ x00- \ x08]? Ein ascii oder ein hexadezimales Zeichen?

Wäre es besser, file.each_line zu verwenden, um die Daten zu erfassen?

File#grep klingt gut.

+0

Ich meine, die Datei enthält mehr als nur die Datenstruktur. Die Datei selbst ist 8000kb, aber es ist cool. Ich werde es mit einer Line-by-Line-Methode versuchen. Außerdem suche ich mit dem '[\ x00- \ x08]' nach den Steuerzeichen am Ende des Textabschnitts. Es ist nicht nur eine CSV-Datei. Es ist eine vollständige Datenbankdatei in einem (undokumentierten) proprietären Datenbankformat. – Sancarn