2017-01-29 10 views
3

Ich kann nicht scheinen, mein letztes Stück herauszufinden, um meine gewünschte Ausgabe zu erreichen.awk double quote Feldtrennzeichen

Ich habe eine Datei mit vielen Einträgen wie folgt aus:

<Stats> 
    <RecNum>45435</RecNum> 
    <Date>2016/12/31</Date> 
    <DayofWeek>6</DayofWeek> 
    <Time>16:35</Time> 
    <Dir>Closing</Dir> 
    <Class>2</Class> 
    <SpeedSpan>1</SpeedSpan> 
    <TimeSpan>1</TimeSpan> 
    <Bucket Speed="34" Count="1"/> 
    <Bucket Speed="35" Count="0"/> 
    <Bucket Speed="36" Count="1"/> 
</Stats> 

ich das Datum, Zeit und Geschwindigkeit drucken möchten, wenn Count = 1 wie folgt:

2016/12/31 16:35 34 
2016/12/31 16:35 36 

Die nächstgelegene Ich habe kommen ist die folgende:

$ awk -F'[ <>]' 'BEGIN {d="d";t="t";} /<Date>/ {d=$3;} /<Time>/ {t=$3;} /Count="1"/ {print d "\t" t "\t" $3;}' speed.xml 

Was mich gibt:

2016/12/31 16:35 Speed="34" 
2016/12/31 16:35 Speed="36" 

Ich habe viele verschiedene Iterationen ausprobiert, aber kann nicht scheinen, nur die Geschwindigkeitszahl ohne den Wortlaut zu bekommen. Ich habe versucht, die "als ein Feld Trennzeichen, aber es scheint nie zu funktionieren, wie erwartet.

Hatte eine awk-Lösung zu finden, aber wenn nicht, kann ich immer ein Python-Programm verwenden, um die unerwünschten Zeichen zu entfernen.

+1

Kasse: [sub (regexp, Ersatz)] (https://www.gnu.org /software/gawk/manual/html_node/String-Functions.html) –

Antwort

4

Jose Ricardo Bustos M.'s helpful XSLT-based answer und Stephen Rauch's helpful Python-based answer bevorzugt sind , weil sie das richtige XML-Parsing verwenden, das sowohl flexibler als auch robuster ist.

Um Ihren awk Befehl zu beheben:

awk -v OFS='\t' -F'[<>]' ' 
    /<Date>/ {d=$3} 
    /<Time>/ {t=$3} 
    /Count="1"/ { 
    split($0, flds, "\"") 
    print d, t, flds[2] 
    } 
' speed.xml 

split($2, flds, "\"") die Linie von Interesse teilt durch " und speichert das Ergebnis in benutzerdefinierter Array flds, der 2.

Auch den "Speed" Attributwert von Index ermöglicht das Extrahieren beachten Sie die Verwendung von -v OFS='\t' - dhSetzen des Ausgabefeld-Trennzeichens auf eine Registerkarte, die eine einfachere print-Anweisung ermöglicht, die die Ausgabefelder aufzählt (awk), um sie implizit durch OFS zu trennen (,).


Nachlese: " zu dem Satz von Feldtrennzeichen Zugabe hätte gearbeitet:

awk -v OFS='\t' -F'["<>]' ' 
    /<Date>/ {d=$3} 
    /<Time>/ {t=$3} 
    /Count="1"/ { print d, t, $3 } 
' file 
+2

Vielen dank. Genau das wollte ich. Ich weiß, dass ich es mit Python getan haben könnte und wahrscheinlich lernen sollte, XSLT zu verwenden, aber es ist für einen ganz bestimmten Anwendungsfall so awk einfach genug zu bedienen war. – brettd0g

+0

@ brettd0g: Verstanden, und froh zu hören, dass es geholfen hat. Gerade ist mir aufgefallen, dass es eine einfachere Lösung gibt - siehe mein Update (obwohl es die 'split()' -Technik im Allgemeinen praktisch ist). – mklement0

+1

Ihre einfachere Lösung hat auch für mich funktioniert. Ich habe oft versucht, das doppelte Zitat zum Feldtrenner hinzuzufügen, aber es würde nicht für mich arbeiten. Deine Arbeit. Vielen Dank. – brettd0g

2

Da Sie erwähnt python:

import xml.dom.minidom 

# Open XML document using minidom parser 
DOMTree = xml.dom.minidom.parseString('<X>' + my_xml + '</X>') 
collection = DOMTree.documentElement 
for record in collection.getElementsByTagName("Stats"): 
    date = record.getElementsByTagName('Date')[0].childNodes[0].data 
    time = record.getElementsByTagName('Time')[0].childNodes[0].data 
    buckets = record.getElementsByTagName('Bucket') 
    for bucket in buckets: 
     x = bucket.getAttribute('Count') 
     if int(bucket.getAttribute('Count')) != 0: 
      print('%s\t%s\t%s' % (date, time, bucket.getAttribute('Speed'))) 

verwendet Daten:

my_xml = """ 
    <Stats> 
     <RecNum>45435</RecNum> 
     <Date>2016/12/31</Date> 
     <DayofWeek>6</DayofWeek> 
     <Time>16:35</Time> 
     <Dir>Closing</Dir> 
     <Class>2</Class> 
     <SpeedSpan>1</SpeedSpan> 
     <TimeSpan>1</TimeSpan> 
     <Bucket Speed="34" Count="1"/> 
     <Bucket Speed="35" Count="0"/> 
     <Bucket Speed="36" Count="1"/> 
    </Stats> 
""" 

Drucke:

2016/12/31 16:35 34 
2016/12/31 16:35 36 
3

Obwohl ich awk mag, empfehle ich xslt zu verwenden, um dies zu tun (mit XSLT können Sie ein XML-Dokument in einem beliebigen Textformat umwandeln). xslt w3schools

file.xsl

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text" omit-xml-declaration="yes"/> 
    <xsl:template match="/"> 
     <xsl:for-each select="Stats/Bucket[@Count='1']"> 
      <xsl:value-of select="../Date"/> 
      <xsl:text>&#x9;</xsl:text> 
      <xsl:value-of select="../Time"/> 
      <xsl:text>&#x9;</xsl:text> 
      <xsl:value-of select="@Speed" /> 
      <xsl:text>&#xa;</xsl:text> 
     </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

ausführen. Wenn Sie irgendeine Art von Linux/Unix verwenden, verwenden Sie die XSLT-1.0-Prozessor xsltproc (Es gibt viele mehr) wie folgt aus:

xsltproc file.xsl file.xml 

Sie erhalten,

2016/12/31 16:35 34 
2016/12/31 16:35 36 
Verwandte Themen