una texto partir lista linea leer guardar gestion formas especifica español crear binarios archivos archivo python string file-io comments skip

texto - leer una linea especifica de un archivo en python



Python: cómo ignorar#comment lines al leer en un archivo (9)

Esta es la forma más corta posible:

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

El método startswith() en una cadena devuelve True si la cadena a la que lo llama comienza con la cadena que ingresó.

Si bien esto está bien en algunas circunstancias, como las secuencias de comandos de shell, tiene dos problemas. Primero, no especifica cómo abrir el archivo. El modo predeterminado para abrir un archivo es ''r'' , que significa ''leer el archivo en modo binario''. Como espera un archivo de texto, es mejor abrirlo con ''rt'' . Aunque esta distinción es irrelevante en los sistemas operativos tipo UNIX, es importante en Windows (y en Mac pre-OS X).

El segundo problema es el manejador de archivo abierto. La función open() devuelve un objeto de archivo, y se considera buena práctica cerrar archivos cuando haya terminado con ellos. Para hacerlo, llame al método close() en el objeto. Ahora, Python probablemente hará esto por ti, eventualmente; en Python los objetos son contados por referencia, y cuando el recuento de referencia de un objeto va a cero, se libera, y en algún momento después de liberar un objeto, Python llamará a su destructor (un método especial llamado __del__ ). Tenga en cuenta que dije probablemente: Python tiene la mala costumbre de no llamar al destructor en los objetos cuyo recuento de referencias cae a cero poco antes de que termine el programa. ¡Supongo que tiene prisa!

Para programas de corta vida como scripts de shell, y particularmente para objetos de archivos, esto no importa. Su sistema operativo limpiará automáticamente todos los identificadores de archivos que se hayan dejado abiertos cuando el programa finalice. Pero si abrió el archivo, leyó el contenido y luego inició una computación larga sin cerrar explícitamente el identificador del archivo primero, es probable que Python deje abierto el manejador del archivo durante su cálculo. Y esa es una mala práctica.

Esta versión funcionará en cualquier versión 2.x de Python, y corrige los dos problemas que discutí anteriormente:

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

Esta es la mejor forma general para las versiones anteriores de Python.

Según lo sugerido por steveha, el uso de la declaración "con" ahora se considera la mejor práctica. Si usa 2.6 o superior, debe escribirlo de esta manera:

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

La instrucción "con" limpiará el manejador del archivo por usted.

En tu pregunta dijiste "líneas que comienzan con #", así que eso es lo que te he mostrado aquí. Si desea filtrar las líneas que comienzan con espacios en blanco opcionales y luego un ''#'', debe quitar el espacio en blanco antes de buscar el ''#''. En ese caso, debe cambiar esto:

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

a esto:

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

En Python, las cadenas son inmutables, por lo que esto no cambia el valor de la line . El método lstrip() devuelve una copia de la cadena con todo su espacio en blanco inicial eliminado.

En Python, acabo de leer una línea de un archivo de texto y me gustaría saber cómo codificar para ignorar los comentarios con un hash # al principio de la línea.

Creo que debería ser algo como esto:

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

Pero soy nuevo en Python y no sé la sintaxis


Recientemente descubrí que una función de generador hace un gran trabajo al respecto. He usado funciones similares para omitir líneas de comentarios, líneas en blanco, etc.

Yo defino mi función como

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

De esa manera, solo puedo hacer

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

Esto es reutilizable en todo mi código, y puedo agregar cualquier manejo / registro / etc adicional. Que yo necesito.


Sé que este es un hilo viejo, pero esta es una función del generador que utilizo para mis propios fines. Quita los comentarios sin importar dónde aparecen en la línea, así como quitando los espacios en blanco iniciales / finales y las líneas en blanco. El siguiente texto fuente:

# 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!

rendirá:

host02 host03 host04

Aquí está el código documentado, que incluye una demostración:

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 non-blank line from ``item`` with comments and leading/trailing whitespace removed. """ 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))

El caso de uso normal será quitar los comentarios de un archivo (es decir, un archivo de hosts, como en mi ejemplo anterior). Si este es el caso, entonces el final del código anterior se modificará para:

if __name__ == ''__main__'': with open(''hosts.txt'', ''r'') as f: hosts = strip_comments(f) for host in hosts: print(''/'%s/''' % host)


Te recomiendo que no ignores toda la línea cuando ves un carácter # ; simplemente ignora el resto de la línea. Puede hacerlo fácilmente con una función de método de cadena llamada partition :

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

partition devuelve una tupla: todo antes de la cadena de partición, la cadena de partición y todo después de la cadena de partición. Entonces, indexando con [0] tomamos solo la parte antes de la cadena de partición.

EDITAR: Si está usando una versión de Python que no tiene partition() , aquí hay un código que puede usar:

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

Esto divide la cadena en un caracter ''#'', luego guarda todo antes de la división. El argumento 1 hace que el método .split() se detenga después de una división; ya que solo estamos agarrando la subcadena número 0 (indexando con [0] ) obtendría la misma respuesta sin el argumento 1 , pero esto podría ser un poco más rápido. (Simplificado desde mi código original gracias a un comentario de @gnr. Mi código original era más complicado sin una buena razón; gracias, @gnr.)

También podría simplemente escribir su propia versión de partition() . Aquí hay una part() llamada 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 notó que ''#'' puede aparecer dentro de una cadena. No es tan fácil manejar este caso correctamente, así que simplemente lo ignoré, pero debería haber dicho algo.

Si su archivo de entrada tiene reglas bastante simples para cadenas entrecomilladas, esto no es difícil. Sería difícil aceptar cualquier cadena legal citada de Python, porque hay comillas simples, comillas dobles y líneas múltiples con una barra invertida que escapa del final de línea, cadenas de comillas triples (usando comillas simples o dobles), y ¡incluso cadenas crudas! La única forma posible de manejar correctamente todo eso sería una máquina de estado complicada.

Pero si nos limitamos a una simple cadena citada, podemos manejarlo con una máquina de estado simple. Incluso podemos permitir una comilla doble entre comillas en la cadena.

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

Realmente no quería complicarme esto en una pregunta etiquetada como "principiante", pero esta máquina de estado es razonablemente simple, y espero que sea interesante.


Tiendo a usar

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

Esto ignorará toda la línea, aunque la respuesta que incluye rpartition tiene mi upvote ya que puede incluir cualquier información antes del #


Una versión más compacta de una expresión de filtrado también puede verse así:

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

(l for ... ) se llama "expresión de generador" que actúa aquí como un iterador de envolvente que filtrará todas las líneas innecesarias del archivo mientras itera sobre él. No lo confunda con lo mismo en corchetes cuadrados [l for ... ] que es una "lista de comprensión" que primero leerá todas las líneas del archivo en la memoria y solo entonces comenzará a iterar sobre él.

A veces puede querer tenerlo menos unidireccional y más legible:

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

Todos los filtros se ejecutarán sobre la marcha en una iteración.


Use regex re.compile("^(?:/s+)*#|(?:/s+)") para omitir las nuevas líneas y comentarios.


Voy a llegar tan tarde, pero el problema de manejar # comentarios de estilo de concha (o estilo de pitón) es muy común.

He estado usando algún código casi cada vez que leo un archivo de texto.
El problema es que no maneja los comentarios entre comillas o escapó correctamente . Pero funciona para casos simples y es fácil.

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

Una solución más robusta es usar 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

Este enfoque shlex no solo maneja las comillas y los escapes correctamente, sino que agrega una gran cantidad de funcionalidades geniales (como la posibilidad de tener archivos de otros archivos si lo desea). No he probado la velocidad en archivos de gran tamaño, pero sí lo suficiente.

El caso común cuando también se divide cada línea de entrada en campos (en espacios en blanco) es aún más simple:

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


puedes usar startswith()

p.ej

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