Ich muss herausfinden, welches Trennzeichen in einer CSV-Datei (Komma, Leerzeichen oder Semikolon) in meinem Ruby-Projekt verwendet wird. Ich weiß, es gibt eine Sniffer-Klasse in Python im csv-Modul, mit der man den Begrenzer einer bestimmten Datei erraten kann. Gibt es etwas Ähnliches in Ruby? Jede Art von Hilfe oder Idee wird sehr geschätzt.Ruby: Wie kann ich das in einer CSV-Datei verwendete Trennzeichen erkennen/intelligent erraten?
Antwort
Sieht aus wie die Py-Implementierung überprüft nur ein paar Dialekte: Excel oder Excel_Tab. So ist eine einfache Implementierung von etwas, das nur überprüft für ","
oder "\t"
ist:
COMMON_DELIMITERS = ['","',"\"\t\""]
def sniff(path)
first_line = File.open(path).first
return nil unless first_line
snif = {}
COMMON_DELIMITERS.each {|delim|snif[delim]=first_line.count(delim)}
snif = snif.sort {|a,b| b[1]<=>a[1]}
snif.size > 0 ? snif[0][0] : nil
end
Hinweis: das wäre den vollständigen Begrenzer zurückkehrt es findet, zum Beispiel ","
, um ,
zu erhalten, könnten Sie die snif[0][0]
zu snif[0][0][1]
ändern.
Auch ich benutze count(delim)
, weil es ein wenig schneller ist, aber wenn Sie ein Trennzeichen, das aus zwei (oder mehr) Zeichen des gleichen Typs wie --
zusammengesetzt ist, dann könnte es jedes Auftreten zweimal (oder mehr) beim Wiegen des Typs, so dass es in diesem Fall besser sein kann, scan(delim).length
zu verwenden.
Mir ist keine Sniffer-Implementierung in der in Ruby 1.9 enthaltenen CSV-Bibliothek bekannt. Es wird versucht, das Zeilentrennzeichen automatisch zu erkennen, aber das Spaltentrennzeichen wird standardmäßig als Komma angenommen.
Eine Idee wäre es, versuchen eine Probe Anzahl von Zeilen (5% der Gesamtmenge vielleicht?) Parsing mit jedem der möglichen Trennzeichen. Unabhängig davon, welcher Separator zu der gleichen Anzahl von Spalten führt, ist wahrscheinlich der richtige Separator.
Hier ist Gary S. Weaver Antwort, wie wir es in der Produktion verwenden. Gute Lösung, die gut funktioniert.
class ColSepSniffer
NoColumnSeparatorFound = Class.new(StandardError)
EmptyFile = Class.new(StandardError)
COMMON_DELIMITERS = [
'","',
'"|"',
'";"'
].freeze
def initialize(path)
@path = path
end
def self.find(path)
new(path: path).find
end
def find
fail EmptyFile unless first
if valid?
delimiters[0][0][1]
else
fail NoColumnSeparatorFound
end
end
private
def valid?
!delimiters.collect(&:last).reduce(:+).zero?
end
# delimiters #=> [["\"|\"", 54], ["\",\"", 0], ["\";\"", 0]]
# delimiters[0] #=> ["\";\"", 54]
# delimiters[0][0] #=> "\",\""
# delimiters[0][0][1] #=> ";"
def delimiters
@delimiters ||= COMMON_DELIMITERS.inject({}, &count).sort(&most_found)
end
def most_found
->(a, b) { b[1] <=> a[1] }
end
def count
->(hash, delimiter) { hash[delimiter] = first.count(delimiter); hash }
end
def first
@first ||= file.first
end
def file
@file ||= File.open(@path)
end
end
Spec
require "spec_helper"
describe ColSepSniffer do
describe ".find" do
subject(:find) { described_class.find(path) }
let(:path) { "./spec/fixtures/google/products.csv" }
context "when , delimiter" do
it "returns separator" do
expect(find).to eq(',')
end
end
context "when ; delimiter" do
let(:path) { "./spec/fixtures/google/products_with_semi_colon_seperator.csv" }
it "returns separator" do
expect(find).to eq(';')
end
end
context "when | delimiter" do
let(:path) { "./spec/fixtures/google/products_with_bar_seperator.csv" }
it "returns separator" do
expect(find).to eq('|')
end
end
context "when empty file" do
it "raises error" do
expect(File).to receive(:open) { [] }
expect { find }.to raise_error(described_class::EmptyFile)
end
end
context "when no column separator is found" do
it "raises error" do
expect(File).to receive(:open) { [''] }
expect { find }.to raise_error(described_class::NoColumnSeparatorFound)
end
end
end
end
- 1. Warum beeinflusst das verwendete Trennzeichen die Gültigkeit einer Regex?
- 2. Wie kann ich die Codierung einer Zeichenfolge in Perl erraten?
- 3. Wie kann DateFormat das geplante Jahrhundert erraten?
- 4. Wie ändere ich das Trennzeichen einer Liste?
- 5. Wie entkommen ich das Trennzeichen in einer Omniture Liste var
- 6. Wie kann ich das Verzeichnis (Dateipfad) Trennzeichen in Perl?
- 7. Wie kann ich die von C# verwendete Datumsformat-Zeichenfolge in das von moment.js verwendete Format konvertieren?
- 8. Wie kann ich das verwendete Gerät von Theano ändern
- 9. Ruby YAML-Trennzeichen
- 10. Kann ich das in TortoiseHg verwendete Diff-Tool ändern?
- 11. Wie könnte ich einen Prüfsummenalgorithmus erraten?
- 12. In Ruby, wie ersetze ich das Fragezeichen in einer Zeichenfolge?
- 13. Hangman: Nicht das Erraten Brief Wiederholung wieder
- 14. Wie kann ich die aktuell verwendete Quote in BQ sehen?
- 15. Wie bekomme ich das Maximum einer beliebigen Funktion in Ruby?
- 16. Wie kann ich die in CFS verwendete Datenstruktur ändern?
- 17. Wie ändere ich das von JasperReports verwendete Gebietsschema?
- 18. Wie kann ich Methoden aus einer Klasse in Ruby aufrufen?
- 19. Wie kann ich mehrere Trennzeichen in Array-Liste verwenden
- 20. Wie kann ich "." als Trennzeichen mit String.split() in Java
- 21. Wie kann ich "{{" und "}} Trennzeichen in Go-Vorlagen entfernen?
- 22. Wie kann ich "{{" und "}} Trennzeichen in Go-Vorlagen entfernen?
- 23. Wie kann ich Ruby in Javascript kompilieren?
- 24. Wie kann ich ungenutzte Methoden in einer Ruby-App finden?
- 25. Wie kann ich die hier verwendete Methode encode/decode zurückentwickeln?
- 26. Teilen einer Zeichenfolge und ignorieren das Trennzeichen in Anführungszeichen
- 27. Wie kann ich Dinge in Ruby inspizieren?
- 28. Wie erraten Vim Hintergrundfarbe auf Xterm?
- 29. Asp.net Erraten Controller Name
- 30. Neuronales Netz Blind erraten
Technisch nur einer von denen ist eine CSV-Datei ... –