2016-04-08 11 views
0

Ich habe Probleme beim Generieren einer Regex, um die folgenden Daten zu analysieren, extrahieren die zwei Dezimalwerte, so dass ich sie in 2 separate Spalten eingeben kann. Was wäre der Ruby- oder Rails-Helfercode, um dies zu tun?String-Daten in Rails analysieren

Hier ist eine visuelle Darstellung der Tabellendaten:

| Percentage Range | 
|------------------| 
| 17 - 20.4%  | 
| 7 - 20.4%  | 
| 17 - 20.4%  | 
| 25 - 30%   | 
| 16.5 - 19.8%  | 
| 25 - 30%   | 
| 16.5 - 19.8%  | 
| 25 - 30%   | 
| 16.5 - 19.8%  | 
------------------- 

Wenn ich importieren, dann durch die obigen Tabellendaten durchlaufen, ich möchte die Dezimalwerte extrahieren und sie zu zwei Variablen zuweisen. Hier ist der nächste kann ich es

@sample_data.each do |p| 

    low_value = p.percentage_range.gsub('regex goes here') #17 for ex 
    high_value = p.percentage_range.gsub('regex goes here') #20.4 for example 
end 
+0

Dieser Ausschnitt oben ist ein Textblock, richtig? –

+0

@AnthonyE Dies ist nur ein Beispiel für die Daten aus einer Tabelle, die ich importiere. Ich möchte es in zwei Spalten extrahieren, wenn Sie in meine Rails-App importieren – ctilley79

+1

Willkommen bei Stack Overflow. Bitte lesen Sie "[fragen]" und "[mcve]". Wir würden gerne Ihre Bemühungen sehen, dies zu lösen. Welchen Code hast du geschrieben, um das Problem zu lösen? Warum hat es nicht funktioniert? Wie es aussieht, möchten Sie, dass wir den Code für Sie schreiben, der nicht der Stack-Overflow-Weg ist. Fügen Sie den Mindestcode hinzu, der zur Veranschaulichung des Problems erforderlich ist. –

Antwort

0

Versuchen Sie, diese regexp

\|\s*([\d+\.]+)\s*-\s*([\d+\.]+)%\s*\| 

Getestet habe ich es hier http://rubular.com/r/r4RPDfqqqU

Ich glaube, Sie Daten Zeile für Zeile lesen können, und wenn Sie Streichhölzer speichern, um sie anders kann es Header oder getrennte Zeile ("--------------") sein.

+0

Die oben angegebenen Beispieldaten sind eine visuelle Darstellung der Tabellendaten, die ich analysieren möchte. die tatsächlichen Daten im Feld wären "17,4 - 20,4%". Ich muss die zwei Dezimalwerte unabhängig von ihrer Größe extrahieren und trennen. Ich entschuldige mich dafür, nicht klarer zu sein lol – ctilley79

+0

entfernen Sie einfach zwei '\ |' (am Anfang und am Ende) von der Regexp – gotva

0

Regex sind rutschige kleine Dinge, und je größer sie sind, desto wahrscheinlicher sind sie außer Kontrolle geraten.

ich so etwas tun würde:

input = <<EOT 
| Percentage Range | 
|------------------| 
| 17 - 20.4%  | 
| 7 - 20.4%  | 
EOT 


input.lines[2 .. -1].map{ |l| l.scan(/[\d.]+/) } 
# => [["17", "20.4"], ["7", "20.4"]] 

Der Kern ist dies die regex /[\d.]+/ in scan, was im Grunde bedeutet: Hier finden Sie Zahlen und Dezimal-Punkte.

Hier ist eine Aufschlüsselung das, was geschieht:

input.lines 
# => ["| Percentage Range |\n", "|------------------|\n", "| 17 - 20.4%  |\n", "| 7 - 20.4%  |\n"] 

lines teilt eine Zeichenfolge auf seinem eingebetteten Line-Enden, eine Reihe von Linien zurück.

input.lines[2 .. -1] 
# => ["| 17 - 20.4%  |\n", "| 7 - 20.4%  |\n"] 

Das gibt die Zeilen zurück, die wir wollen.

Sie sollten in der Lage sein, den Rest herauszufinden.


auf dem Code der Suche:

@sample_data.each do || 

    low_value = p.percentage_range.gsub('regex goes here') #17 for ex 
    high_value = p.percentage_range.gsub('regex goes here') #20.4 for example 
end 

Es gibt mehrere Dinge falsch:

  • || ist nicht notwendig, noch Ihr Code hilft verständlicher sein.
  • Was ist ?
  • Was ist percentage_range?
  • gsub ist eine globale Substitution zu tun, und ist hier unpassend. Ersetze Sachen nicht, wenn du passen/finden willst. Es gibt einen großen Unterschied im Zweck und normalerweise wird man den anderen nicht ersetzen.

Wenn Sie nicht wollen, scan verwenden, die die offensichtliche Go-to-Methode hierfür ist:

scan(pattern) → Array

[...]

Beide Formen iterieren durch str und stimmen mit dem Muster überein (das ein Regexp oder ein String sein kann). Für jede Übereinstimmung wird ein Ergebnis generiert und entweder zum Ergebnis-Array hinzugefügt oder an den Block übergeben. Wenn das Muster keine Gruppen enthält, besteht jedes einzelne Ergebnis aus der übereinstimmenden Zeichenfolge $ &. Wenn das Muster Gruppen enthält, ist jedes einzelne Ergebnis selbst ein Array, das einen Eintrag pro Gruppe enthält.

a = "cruel world" 
a.scan(/\w+/)  #=> ["cruel", "world"] 
a.scan(/.../)  #=> ["cru", "el ", "wor"] 
a.scan(/(...)/)  #=> [["cru"], ["el "], ["wor"]] 
a.scan(/(..)(..)/) #=> [["cr", "ue"], ["l ", "wo"]] 

dann könnte man andere Möglichkeiten, die Daten verwenden, greifen:

low, high = '17 - 20.4%'.scan(/[\d.]+/) 
# => ["17", "20.4"] 

low, high = '17 - 20.4%'.match(/([\d.]+)\s+-\s+([\d.]+)/).captures 
# => ["17", "20.4"] 

low, high = '17 - 20.4%'.tr(' %', '').split('-') 
# => ["17", "20.4"] 

Beachten Sie, dass das Muster für match viel komplexer ist und weniger lesbar. Es könnte etwas werden mit Variationen vereinfacht wie:

low, high = '17 - 20.4%'.match(/([\d.]+).+?([\d.]+)%/).captures 
# => ["17", "20.4"] 

aber scan bleibt mehr einfach und auf den Punkt und verwendet ein triviales Muster.

+0

Ich entschuldige mich dafür, auf meiner Frage nicht klar zu sein. Die obige Tabelle ist einfach eine visuelle Darstellung von Beispieldaten in einer Datenbanktabelle.Die tatsächlichen Daten im Feld wären "17,4 - 20,4%". Ich muss die zwei Dezimalwerte in zwei Variablen extrahieren und trennen. Ich entschuldige mich dafür, nicht klarer zu sein, lol. Diese Frage wurde zu einem Cluster. – ctilley79

+0

Es ist wirklich wichtig, die Frage vor der Nachfrage auszudenken und die notwendigen Informationen zur Verfügung zu stellen. "[ask]" geht hier gut vor, besonders die Links am Ende der Seite. Die Technik, die ich zeigte, wird genauso gut in Ihrem neuen Szenario funktionieren wie die andere. Sie müssen herausfinden, wie Sie es anwenden. –

+0

Wenn die Daten wirklich in einer Tabelle sind, dann macht Ihre Frage noch weniger Sinn und ist ein XY-Problem, bei dem Sie nach Y statt X fragen, das hätte sein sollen "Wie extrahiere ich Daten aus einer Datenbank" und ist ein Kernpunkt in jedem [Tutorial über Rails Active Record] (http://guides.rubyonrails.org/active_record_basics.html). –

0

nicht sicher, ob dies ist, was Sie fordern, aber die folgenden Griffe tokenization und für jede Zeile Parsen:

each_row.map do |row| 
    value_pair = row.scan(/\d+.?\d+ - \d+\.?\d+/).map do |token| 
    token.split(" - ").map(&:to_f) 
    end 

    # Unwrap 
    value_pair = Array(value_pair) 

    { 
    highest: value_pair[0], 
    lowest: value_pair[1] 
    } 
end 

P. S. Bitte versuchen Sie genauer zu sein in Ihrer Eingabeaufforderung, mussten Sie mehr als einmal umschreiben, wie Sie Ihre Frage geändert haben.

+1

Ein guter Hinweis darauf, dass eine Frage nicht gut definiert ist, ist die Anzahl der Kommentare, die unmittelbar auf die Frage folgen. Wenn ich mehr als zwei sehe, lese ich die Frage sorgfältig und wenn es Antworten mit mehreren Kommentaren gibt, dann bin ich mir sicher, dass es ein Definitionsproblem gibt, und markieren Sie die Frage als solche und bitten Sie um Klarstellung. Es ist besser, eine schlecht definierte Frage nicht zu beantworten, da sie der Website nicht zugute kommt. antworten Sie umgekehrt genau definierte Fragen. –

+1

In der Tat, das ist ein guter Rat. –