Frage

In Python habe ich gerade gelesen, eine Linie eine Textdatei bilden und ich würde gerne wissen, wie mit einem Hash # am Anfang der Zeile zu ignorieren Kommentare zu codieren.

Ich denke, es sollte wie folgt sein:

for 
   if line !contain #
      then ...process line
   else end for loop 

Aber ich bin neu in Python und ich weiß nicht, die Syntax

War es hilfreich?

Lösung

Sie verwenden können, starts ()

zB

for line in open("file"):
    li=line.strip()
    if not li.startswith("#"):
        print line.rstrip()

Andere Tipps

Ich empfehle Ihnen nicht die ganze Zeile ignorieren, wenn Sie einen # Charakter sehen; einfach ignoriert den Rest der Zeile. Sie können mit einem String-Methode Funktion aufgerufen partition so leicht tun:

with open("filename") as f:
    for line in f:
        line = line.partition('#')[0]
        line = line.rstrip()
        # ... do something with line ...

partition gibt ein Tupel: alles vor der Teilung Zeichenfolge, die Partition Zeichenfolge, und alles nach der Teilung String. Also, durch Indizieren mit [0] nehmen wir nur den Teil vor der Partition String.

EDIT: Wenn Sie eine Version von Python verwenden, die nicht partition() hat, ist hier Code, den Sie verwenden:

with open("filename") as f:
    for line in f:
        line = line.split('#', 1)[0]
        line = line.rstrip()
        # ... do something with line ...

Dies teilt den String auf einem Zeichen ‚#‘, dann ist alles vor der Spaltung hält. Das Argument 1 macht den .split() Verfahren Anschlag Nach einem Split; da wir Teilzeichenfolge Grabbing sind nur die 0. (Indizierung von mit [0]) Sie würden die gleiche Antwort ohne 1 Argument bekommen, aber dies könnte etwas schneller sein. (Vereinfachtes von meinem ursprünglichen Code durch einen Kommentar von @gnr Mein Original-Code war Messier für keinen guten Grund,.. Danke, @gnr)

Sie können auch nur Ihre eigene Version von partition() schreiben. Hier ist ein genannt part():

def part(s, s_part):
    i0 = s.find(s_part)
    i1 = i0 + len(s_part)
    return (s[:i0], s[i0:i1], s[i1:])

@dalle stellte fest, dass '#' in einem String erscheinen. Es ist nicht so einfach, diesen Fall richtig zu handhaben, so dass ich es einfach ignoriert, aber ich soll etwas gesagt hat.

Wenn Ihre Eingabedatei einfach genug Regeln für Strings in Anführungszeichen hat, ist dies nicht schwer. Es wäre schwierig, wenn Sie irgendeine rechtlichen Python Zeichenfolge in Anführungszeichen akzeptiert, weil es in einfachen Anführungszeichen, doppelte Anführungszeichen, mehrzeilige Anführungszeichen mit einem Backslash ist entkommen, die End-of-line, Dreier- Strings in Anführungszeichen (einfache oder doppelte Anführungszeichen), und sogar rohe Strings! Der einzig mögliche Weg, um all korrekt zu behandeln, die eine komplizierte Zustandsmaschine sein würde.

Aber wenn wir uns auf nur eine einfache Anführungszeichen begrenzen, können wir es mit einer einfachen Zustandsmaschine handhaben. Wir können sogar einen umgekehrten Schrägstrich Anführungszeichen Anführungszeichen innerhalb der Zeichenfolge ermöglichen.

c_backslash = '\\'
c_dquote = '"'
c_comment = '#'


def chop_comment(line):
    # a little state machine with two state varaibles:
    in_quote = False  # whether we are in a quoted string right now
    backslash_escape = False  # true if we just saw a backslash

    for i, ch in enumerate(line):
        if not in_quote and ch == c_comment:
            # not in a quote, saw a '#', it's a comment.  Chop it and return!
            return line[:i]
        elif backslash_escape:
            # we must have just seen a backslash; reset that flag and continue
            backslash_escape = False
        elif in_quote and ch == c_backslash:
            # we are in a quote and we see a backslash; escape next char
            backslash_escape = True
        elif ch == c_dquote:
            in_quote = not in_quote

    return line

Ich wollte nicht wirklich in Frage dieses komplizierte „Anfänger“, aber dieser Zustand Maschine ist getaggt bekommen ziemlich einfach, und ich hoffe, es wird interessant sein.

ich in diesem späten komme, aber das Problem Shell-Stil (oder Python-Stil) # Umgang mit Anmerkungen ist ein sehr allgemein.

Ich habe einige Code benutze fast jedes Mal las ich eine Textdatei.
Das Problem ist, dass es nicht zitiert oder entkam Kommentare nicht ordnungsgemäß behandeln . Aber es funktioniert für einfache Fälle und ist einfach.

for line in whatever:
    line = line.split('#',1)[0].strip()
    if not line:
        continue
    # process line

Eine robustere Lösung ist shlex :

import shlex
for line in instream:
    lex = shlex.shlex(line)
    lex.whitespace = '' # if you want to strip newlines, use '\n'
    line = ''.join(list(lex))
    if not line:
        continue
    # process decommented line

Dieser shlex Ansatz nicht nur Griffe Zitate und entkommt richtig, fügt es eine Menge cooler Funktionen (wie die Fähigkeit, Dateien Quellen andere Dateien zu haben, wenn Sie möchten). Ich habe es nicht für Geschwindigkeit auf große Dateien getestet, aber es ist flink genug von Kleinkram.

Der gemeinsame Fall, wenn Sie auch jede Eingabezeile in Felder (auf Leerzeichen) Aufspalten ist noch einfacher:

import shlex
for line in instream:
    fields = shlex.split(line, comments=True)
    if not fields:
        continue
    # process list of fields 

Dies ist die kürzest mögliche Form:

for line in open(filename):
  if line.startswith('#'):
    continue
  # PROCESS LINE HERE

Die startswith() Methode auf eine Zeichenfolge gibt True zurück, wenn die Zeichenfolge Sie es auf beginnt mit der Zeichenfolge rufen Sie in übergeben.

Während dies unter bestimmten Umständen, wie Shell-Skripte in Ordnung ist, hat es zwei Probleme. Erstens, geben Sie es nicht, wie die Datei zu öffnen. Der Standardmodus für das Öffnen einer Datei ist 'r', welche ‚gelesen, die Datei im Binärmodus‘ bedeutet. Da Sie eine Textdatei erwar ist es besser, es zu öffnen mit 'rt'. Obwohl diese Unterscheidung auf UNIX-ähnlichen Betriebssystemen irrelevant ist, ist es wichtig, auf Windows (und auf Pre-OS X Macs).

Das zweite Problem ist die offene Datei-Handle. Die open() Funktion gibt ein Dateiobjekt, und es ist eine gute Praxis betrachtet Dateien zu schließen, wenn Sie mit ihnen fertig sind. Um dies zu tun, rufen Sie die close() Methode für das Objekt. Nun, Python wird wahrscheinlich dies für Sie tun, schließlich; in Python-Objekte sind mit Referenzzählung, und wenn ein Referenzzählung des Objekts geht es wird befreit auf Null, und bei einigen Punkt nach einem Objekt freigegeben wird Python seine Destruktoraufrufs wird (eine besondere Methode genannt __del__). Beachten Sie, dass ich sagte: wahrscheinlich: Python hat eine schlechte Gewohnheit, nicht tatsächlich den Aufruf der destructor auf Objekte, deren Referenzzähler fällt kurz auf Null, bevor das Programm beendet wird. Ich denke, es ist in Eile!

Für kurzlebige Programme wie Shell-Skripten und insbesondere für Dateiobjekte, dies keine Rolle spielt. Das Betriebssystem wird automatisch jede Datei aufzuräumen Griffe offen gelassen, wenn das Programm beendet ist. Aber wenn Sie die Datei geöffnet wird, lesen Sie den Inhalt, dann eine lange Berechnung gestartet, ohne vorher die Datei-Handle explizit zu schließen, ist Python wahrscheinlich das Datei-Handle geöffnet während der Berechnung zu verlassen. Und das ist eine schlechte Praxis.

Diese Version wird in jeder 2.x-Version von Python arbeiten, und Korrekturen sowohl die Probleme, die ich oben beschrieben:

f = open(file, 'rt')
for line in f:
  if line.startswith('#'):
    continue
  # PROCESS LINE HERE
f.close()

Dies ist die beste allgemeine Form für ältere Versionen von Python.

Wie steveha vorgeschlagen, mit dem „mit“ Aussage gilt heute als Best Practice. Wenn Sie mit 2.6 oder höher sollten Sie es auf diese Weise schreiben:

with open(filename, 'rt') as f:
  for line in f:
    if line.startswith('#'):
      continue
    # PROCESS LINE HERE

Die „mit“ Anweisung wird das Datei-Handle für Sie aufzuräumen.

In Ihrer Frage gesagt, Sie „Zeilen, die mit # beginnen“, so dass das, was ich Ihnen hier gezeigt. Wenn Sie möchten, Linien, um herauszufiltern, die mit Anfang optional Leerzeichen und und ein ‚#‘, sollten Sie das Leerzeichen abzustreifen, bevor die ‚#‘ suchen. In diesem Fall sollten Sie dies ändern:

    if line.startswith('#'):

folgt aus:

    if line.lstrip().startswith('#'):

In Python-Strings sind unveränderlich, so dass diese nicht den Wert von line ändern. Die lstrip() Methode gibt eine Kopie des Strings mit allen führenden Leerzeichen entfernt.

Ich habe vor kurzem, dass eine Generatorfunktion hat eine große Aufgabe dieses gefunden. Ich habe ähnliche Funktionen verwendet, um Kommentarzeilen, Leerzeilen zu überspringen, etc.

Ich definiere meine Funktion als

def skip_comments(file):
    for line in file:
        if not line.strip().startswith('#'):
            yield line

Auf diese Weise kann ich nur tun

f = open('testfile')
for line in skip_comments(f):
    print line

Dies ist wiederverwendbar in allen meinen Code, und ich kann jede zusätzliche Handhabung / logging / etc. dass ich brauche.

Ich weiß, dass dies ist ein alter Thread, aber dies ist eine Generatorfunktion, die ich für meine eigenen Zwecke. Es streift Kommentare, egal wo sie erscheint in der Leitung, sowie Stripping Vorlauf- / Nachlauf Leerzeichen und Leerzeilen. Der folgende Quelltext:

# Comment line 1
# Comment line 2

# host01  # This host commented out.
host02  # This host not commented out.
host03
  host04  # Oops! Included leading whitespace in error!

wird ergeben:

host02
host03
host04

Hier ist dokumentiert Code, der eine Demo enthält:

def strip_comments(item, *, token='#'):
    """Generator. Strips comments and whitespace from input lines.

    This generator strips comments, leading/trailing whitespace, and
    blank lines from its input.

    Arguments:
        item (obj):  Object to strip comments from.
        token (str, optional):  Comment delimiter.  Defaults to ``#``.

    Yields:
        str:  Next uncommented non-blank line from ``item`` with
            comments and leading/trailing whitespace stripped.

    """

    for line in item:
        s = line.split(token, 1)[0].strip()
        if s:
            yield s


if __name__ == '__main__':
    HOSTS = """# Comment line 1
    # Comment line 2

    # host01  # This host commented out.
    host02  # This host not commented out.
    host03
      host04  # Oops! Included leading whitespace in error!""".split('\n')


    hosts = strip_comments(HOSTS)
    print('\n'.join(h for h in hosts))

Der normale Anwendungsfall wird die Kommentare aus einer Datei strippen (das heißt eine Host-Datei, wie in meinem Beispiel oben). Wenn dies der Fall ist, dann wäre das hintere Ende des obigen Codes geändert:

if __name__ == '__main__':
    with open('hosts.txt', 'r') as f:
        hosts = strip_comments(f)

    for host in hosts:
        print('\'%s\'' % host)

Eine kompaktere Version eines Filterausdruck kann auch wie folgt aussehen:

for line in (l for l in open(filename) if not l.startswith('#')):
    # do something with line

(l for ... ) wird „Generator Ausdruck“ genannt, was hier als Verpackungs Iterator fungiert, die alle nicht benötigten Zeilen aus der Datei filtert, während sie über sie iterieren. Nicht verwechseln mit der gleichen Sache in eckigen brakets [l for ... ], die eine „Liste Verständnis“ ist, die zuerst alle Zeilen aus der Datei in den Speicher geladen wird und erst dann beginnt, über sie iterieren.

Manchmal möchten Sie vielleicht weniger ein Liney haben und besser lesbar:

lines = open(filename)
lines = (l for l in lines if ... )
# more filters and mappings you might want
for line in lines:
    # do something with line

Alle Filter werden im laufenden Betrieb in einer Iteration ausgeführt werden.

regex re.compile("^(?:\s+)*#|(?:\s+)") Mit den neuen Linien und Kommentare überspringen.

Ich neige dazu verwenden,

for line  in lines:
    if '#' not in line:
        #do something

Das wird die ganze Zeile ignorieren, obwohl die Antwort, die rpartition hat meinen upvote enthält, wie es keine Informationen aus der Zeit vor dem # include kann

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top