3 votes

Faites correspondre l'une des deux assertions en arrière.

Je tente de remplir une colonne dans un Pandas.DataFrame en extrayant l'id d'un périphérique à partir d'un fichier journal. Le problème est que l'id peut être précédé de deux motifs distincts comme suit :

Motif 1:

(?<=cameraId=\')([a-z0-9-]+))

Motif 2:

(?<=/live/)([a-z0-9-]+)

Remarque : il n'y a pas de moyen pour une ligne d'avoir les deux motifs

Le problème est que j'utilise la méthode Pandas.String.str.findall(), et je veux que les deux motifs soient remplis.

Je peux obtenir le résultat souhaité avec succès comme le montre le code ci-dessous :

import pandas as pd

line_1 = 'INFO:2021-04-19 00:25:10,647:instance_manager.py:MainProcess:1:got event notificationName=\'DETECTION_STARTED\' cameraId=\'ab1c-ab6c-a6f6-a6d6-ab666\' timestamp=\'2021-04-19T00:24:08.192169Z\''

line_2 = 'INFO:2021-04-19 00:25:11,278:instance_manager.py:MainProcess:1:An old record record for the stream rtsp://127.0.1.1:6666/live/a001-a00a-0016-a006-ab606.stream was successfully updated in the DB!'

df = pd.DataFrame(columns=['type', 'ts', 'process', 'subprocess', 'line', 'message'])

line_1_parsed = pd.Series([line_1]).str.extract(r'(?P[^:]+):(?P.+,\d+):(?P[^:]+):(?P[^:]+):(?P[^:]+):(?P[^$]+)')
line_2_parsed = pd.Series([line_2]).str.extract(r'(?P[^:]+):(?P.+,\d+):(?P[^:]+):(?P[^:]+):(?P[^:]+):(?P[^$]+)')

df =df.append(line_1_parsed, ignore_index=True)
df =df.append(line_2_parsed, ignore_index=True)

df.loc[:, 'cam_id'] = df.loc[:, 'message'].str.findall('(?<=cameraId=\')([a-z0-9-]+)|(?<=/live/)([a-z0-9-]+)')
df

, mais ils sont retournés sous forme de tuples (motif 1, motif 2) comme indiqué dans la Sortie actuelle :

Sortie actuelle:

    type    ts  process     subprocess  line    message     cam_id
0   INFO    2021-04-19 00:25:10,647     instance_manager.py     MainProcess     1   got event notificationName='DETECTION_STARTED'...   [(ab1c-ab6c-a6d6-ab666, )]
1   INFO    2021-04-19 00:25:11,278     instance_manager.py     MainProcess     1   An old record record for the stream rtsp://127...   [(, a001-a00a-0016-a006-ab606)]

Je comprends que cela est dû au fait qu'il essaie les deux motifs et renvoie les correspondances pour les deux, mais je préférerais qu'il n'y ait que le motif réussi.

Je peux le faire en extrayant manuellement de la manière suivante :

df.loc[:, 'cam_id'] = df.loc[:, 'cam_id'].apply(lambda cam_id_tuple: cam_id_tuple[0][0] if cam_id_tuple[0][0] != '' else cam_id_tuple[0][1])
df

mais c'est plutôt une solution fastidieuse, et non extensible, au cas où je voudrais ajouter des motifs.

Sortie souhaitée:

    type    ts  process     subprocess  line    message     cam_id
0   INFO    2021-04-19 00:25:10,647     instance_manager.py     MainProcess     1   got event notificationName='DETECTION_STARTED'...   [ab1c-ab6c-a6d6-ab666]
1   INFO    2021-04-19 00:25:11,278     instance_manager.py     MainProcess     1   An old record record for the stream rtsp://127...   [a001-a00a-0016-a006-ab606]`

Nonte: la colonne cam_id contient des chaînes de caractères et non des tuples

Merci d'avance.

4voto

Shubham Sharma Points 39381

Nous pouvons utiliser str.extract avec un motif regex ayant un seul groupe de capture

df['message'].str.extract(r'(?:cameraId=\'|/live/)([a-z0-9-]+)', expand=False)

0    ab1c-ab6c-a6f6-a6d6-ab666
1    a001-a00a-0016-a006-ab606
Name: message, dtype: object

Détails du Regex :

  • (?:cameraId=\'|/live/): Groupe non capturant
    • cameraId=\' : La première alternative correspond aux caractères cameraId=' littéralement
    • /live/ : La deuxième alternative correspond aux caractères /live/ littéralement
  • ([a-z0-9-]+) : Premier groupe de capture
    • [a-z0-9-]+ : Correspond à n'importe quel caractère présent dans la liste [a-z0-9-] une ou plusieurs fois

Consultez le démo de regex en ligne

3voto

RavinderSingh13 Points 29608

Avec les exemples que vous avez montrés, vous pourriez également essayer la fonction suivante.

df['message'].str.extract(r'.*(?:live\/|cameraId=\')([^\'.]*)', expand=False)

La sortie du code ci-dessus sera :

0   ab1c-ab6c-a6f6-a6d6-ab666
1   a001-a00a-0016-a006-ab606

Voici la démonstration en ligne du code ci-dessus

Explication: Ajout d'une explication détaillée pour le code ci-dessus.

.*(?:live\/|cameraId=\')  ##Du début du match jusqu'à live/ OU cameraId=' dans un groupe de non-capture.
([^\'.]*)                 ##Création d'un groupe de capture et correspondant jusqu'à ' OU . ici.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X