Tengo un archivo de registro que contiene líneas formateadas como se muestra a continuación. Quiero analizar los valores justo al lado de las subcadenas element=(string), time=(guint64) y ts=(guint64) y guardarlos en una lista que contendrá listas separadas para cada línea:

0:00:00.336212023 62327 0x55f5ca5174a0 TRACE             GST_TRACER :0:: element-latency, element-id=(string)0x55f5ca532a60, element=(string)rawvideoparse0, src=(string)src, time=(guint64)852315, ts=(guint64)336203035;
0:00:00.336866520 62327 0x55f5ca5176d0 TRACE             GST_TRACER :0:: element-latency, element-id=(string)0x55f5ca53f860, element=(string)nvh264enc0, src=(string)src, time=(guint64)6403181, ts=(guint64)336845676;

El resultado final se vería así: [['rawvideoparse0', 852315, 336203035], ['nvh264enc0', 6403181, 336845676]].

Probablemente debería usar los métodos de división o división de cadenas de Python para obtener las partes relevantes en cada línea, pero no puedo encontrar una solución corta que pueda generalizarse para los valores que estoy buscando. Tampoco sé cómo lidiar con el hecho de que los valores element y time se terminan con una coma, mientras que ts se termina con un punto y coma (sin escribir condicional por separado para los dos casos). ¿Cómo puedo lograr esto usando los métodos de manipulación de cadenas en Python?

1
chronosynclastic 7 oct. 2019 a las 18:29

3 respuestas

La mejor respuesta

Regex estaba destinado a esto:

lines = """
0:00:00.336212023 62327 0x55f5ca5174a0 TRACE             GST_TRACER :0:: element-latency, element-id=(string)0x55f5ca532a60, element=(string)rawvideoparse0, src=(string)src, time=(guint64)852315, ts=(guint64)336203035;
0:00:00.336866520 62327 0x55f5ca5176d0 TRACE             GST_TRACER :0:: element-latency, element-id=(string)0x55f5ca53f860, element=(string)nvh264enc0, src=(string)src, time=(guint64)6403181, ts=(guint64)336845676;
"""

import re

pattern = re.compile(".*element-id=\\(string\\)(?P<elt_id>.*), element=\\(string\\)(?P<elt>.*), src=\\(string\\)(?P<src>.*), time=\\(guint64\\)(?P<time>.*), ts=\\(guint64\\)(?P<ts>.*);")
for l in lines.splitlines():
    match = pattern.match(l)
    if match:
        results = match.groupdict()
        print(results)

Proporciona los siguientes diccionarios (tenga en cuenta que los grupos capturados se han nombrado en la expresión regular anterior usando (?P<name>...), por eso tenemos estos nombres):

{'elt_id': '0x55f5ca532a60', 'elt': 'rawvideoparse0', 'src': 'src', 'time': '852315', 'ts': '336203035'}
{'elt_id': '0x55f5ca53f860', 'elt': 'nvh264enc0', 'src': 'src', 'time': '6403181', 'ts': '336845676'}

Puede hacer que este patrón de expresiones regulares sea aún más genérico, ya que todos los elementos comparten una estructura común <name>=(<type>)<value>:

pattern2 = re.compile("(?P<name>[^,;\s]*)=\\((?P<type>[^,;]*)\\)(?P<value>[^,;]*)")
for l in lines.splitlines():
    all_interesting_items = pattern2.findall(l)
    print(all_interesting_items)

Cede:

[]
[('element-id', 'string', '0x55f5ca532a60'), ('element', 'string', 'rawvideoparse0'), ('src', 'string', 'src'), ('time', 'guint64', '852315'), ('ts', 'guint64', '336203035')]
[('element-id', 'string', '0x55f5ca53f860'), ('element', 'string', 'nvh264enc0'), ('src', 'string', 'src'), ('time', 'guint64', '6403181'), ('ts', 'guint64', '336845676')]

Tenga en cuenta que, en todos los casos, https://regex101.com/ es su amigo para la depuración de expresiones regulares :)

1
smarie 7 oct. 2019 a las 16:37

Aquí hay una posible solución usando una serie de comandos divididos:

output = []
with open("log.txt") as f:
    for line in f:
        values = []
        line = line.split("element=(string)", 1)[1]
        values.append(line.split(",", 1)[0])
        line = line.split("time=(guint64)", 1)[1]
        values.append(int(line.split(",", 1)[0]))
        line = line.split("ts=(guint64)", 1)[1]
        values.append(int(line.split(";", 1)[0]))
        output.append(values)
1
Riccardo Bucco 7 oct. 2019 a las 15:50

Esta no es la solución más rápida, pero probablemente así es como lo codificaría para facilitar la lectura.

# create empty list for output
list_final_output = []

# filter substrings
list_filter = ['element=(string)', 'time=(guint64)', 'ts=(guint64)']

# open the log file and read in the lines as a list of strings
with open('so_58272709.log', 'r') as f_log:
    string_example = f_log.read().splitlines()
print(f'string_example: \n{string_example}\n')

# loop through each line in the list of strings
for each_line in string_example:

    # split each line by comma
    list_split_line = each_line.split(',')

    # loop through each filter substring, include filter
    filter_string = [x for x in list_split_line if (list_filter[0] in x
                                                    or list_filter[1] in x
                                                    or list_filter[2] in x
                                                   )]

    # remove the substring
    filter_string = [x.replace(list_filter[0], '') for x in filter_string]
    filter_string = [x.replace(list_filter[1], '') for x in filter_string]
    filter_string = [x.replace(list_filter[2], '') for x in filter_string]

    # store results of each for-loop
    list_final_output.append(filter_string)

# print final output
print(f'list_final_output: \n{list_final_output}\n')
0
pk2019 7 oct. 2019 a las 16:26
58272709