Estrarre la stringa e il numero da una stringa che è in formato multiplo usando regex in Python?

Sep 03 2020

Sto cercando di analizzare una stringa usando regex che è in un formato particolare per ricavarne i dettagli. Posso avere la mia stringa in due formati:

Primo formato

Un modo è avere un file foldername-version.tgz. Qui foldernamepuò essere qualsiasi stringa in qualsiasi formato. Può averne un altro o più -o qualsiasi altra cosa.

Per esempio:

  • ciao-1234.tgz: Questo dovrebbe darmi FolderNamecome helloe Versioncome1234
  • world-12345.tgz: Questo dovrebbe darmi FolderNamecome worlde Versioncome12345
  • ciao-21234-12345.tgz: Questo dovrebbe darmi FolderNamecome hello-21234e Versioncome12345
  • ciao-21234-a-12345.tgz: Questo dovrebbe darmi FolderNamecome hello-21234-ae Versioncome12345

Secondo formato

Un altro modo è avere foldername-version-environment.tgz. Anche in questo caso foldernamepuò essere qualsiasi stringa in qualsiasi formato. Anche l'ambiente stringa può essere solo dev, stage, prode nient'altro quindi ho bisogno di aggiungere controllo su quel pure.

Per esempio:

  • hello-1234-dev.tgz: Questo dovrebbe darmi FolderNamecome helloe Versioncome1234
  • world-12345-stage.tgz: Questo dovrebbe darmi FolderNamecome worlde Versioncome12345
  • ciao-21234-12345-prod.tgz: Questo dovrebbe darmi FolderNamecome hello-21234e Versioncome12345
  • ciao-21234-a-12345-prod.tgz: Questo dovrebbe darmi FolderNameas hello-21234-ae Versionas12345

Dichiarazione problema

Quindi, con i due formati precedenti, ho bisogno di estrarre FolderNamee Versiondalla mia stringa. Ho provato con la regex sotto ma non funziona sulle mie stringhe che sono nel secondo formato ma voglio che il mio codice funzioni su entrambi i formati.

#sample example string which can be in first or second format
exampleString = hello-21234-12345-prod.tgz
build_found = re.search(r'[\d.-]+.tgz', exampleString)
version = build_found.group().replace(".tgz", "")
folderName = exampleString.split(version)[0]

Cosa sto facendo qui?

Risposte

1 TimBiegeleisen Sep 03 2020 at 05:37

Io userei:

inp = "some text hello-21234-a-12345.tgz some more text"
parts = re.findall(r'\b([^\s-]+(?:-[^-]+)*)-(\d+)(?:-[^-]+)*\.\w+\b', inp)
print("FolderName: " + parts[0][0])
print("Version: " + parts[0][1])

Questo stampa:

FolderName: hello-21234-a
Version: 12345
tzaman Sep 03 2020 at 05:39

Usa i gruppi per specificare le diverse sezioni del motivo. Puoi anche nominarli per una più facile estrazione in seguito:

pattern = re.compile(r"(?P<FolderName>.+)-(?P<Version>\d+)(?:-(?P<Env>dev|stage|prod))?\.tgz")

m = pattern.match(ex)
print(m.groups())
# ('hello-21234', '12345', 'prod')
print(m.group('FolderName'), m.group('Version'), m.group('Env'))
# ('hello-21234', '12345', 'prod')

ex2 = "hello-21234-1234.tgz" # No environment
m = pattern.match(ex)
print(m.groups())
# ('hello-21234', '12345', None)
print(m.group('FolderName'), m.group('Version'), m.group('Env'))
# ('hello-21234', '12345', None)
RichieV Sep 03 2020 at 05:39

Vedi se questo modello funziona

import re
exampleString = 'hello-21234-12345-prod.tgz'
build_found = re.search(r'([\w-]+)-(\d+)-(dev|stage|prod)?', exampleString)

folder_name = build_found[1]
version = build_found[2]
environment = build_found[3]

print(folder_name)
print(version)
print(environment)

Produzione

hello-21234
12345
prod
MatthewRussell Sep 03 2020 at 05:41

Sicuramente non è l'approccio migliore, ma ecco un'idea.

Inizia determinando se hai il primo o il secondo caso.

-(dev|stage|prod)\.tgz$

Questa regex determinerà se hai o meno il caso 1 o 2.

Se è il caso 1, puoi estrarre il nome della cartella con:

.*-

E puoi estrarre la versione con:

-\d+.tgz$

Se è il caso 2, puoi estrarre il nome cartella / numero versione combinati con:

.*-

Da lì, puoi estrarre il nome della cartella con (di nuovo):

.*-

E il numero di versione con:

-\d+
DrewShafer Sep 03 2020 at 05:34

È necessario utilizzare un'espressione regolare che acquisisca i componenti che stai cercando all'interno della stringa, quindi utilizzare .groups()per estrarre le acquisizioni. Questo ha funzionato nei miei test:

re.search(r'^(.+)-(\d+)\D*$', exampleString)

esempio in ipython:

In [1]: import re

In [2]: s1 = 'hello-21234-12345-prod.tgz'

In [3]: s2 = 'hello-1234.tgz'

In [4]: re.search(r'^(.+)-(\d+)\D*$', s1).groups()
Out[4]: ('hello-21234', '12345')

In [5]: re.search(r'^(.+)-(\d+)\D*$', s2).groups()
Out[5]: ('hello', '1234')

Il trucco sta nell'acquisizione dei gruppi ( (...)) all'interno dell'espressione regolare r'^(.+)-(\d+)\D*$'. Ci sono due gruppi: in realtà è più facile decodificarlo guardando prima il secondo gruppo di acquisizione, poi il primo.

La seconda parte della regex: r'(\d+)\D*$'corrisponde alla serie finale di \dcifre. Sai che è l'ultima serie di cifre, perché la \D*$parte corrisponderà e inghiottirà tutti i caratteri non numerici fino alla fine della stringa.

La prima parte della regex: r'^(.+)-'corrisponde a tutto prima della seconda parte. Cattura tutto tranne il "-"carattere e ti dà il FolderName

Nota che avrai bisogno di qualcosa di un po 'più complesso se hai caratteri numerici nel tuo environmento nel finale del file (come se stai usando la compressione bzip2)