Estrarre la stringa e il numero da una stringa che è in formato multiplo usando regex in Python?
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
FolderNamecomehelloeVersioncome1234 - world-12345.tgz: Questo dovrebbe darmi
FolderNamecomeworldeVersioncome12345 - ciao-21234-12345.tgz: Questo dovrebbe darmi
FolderNamecomehello-21234eVersioncome12345 - ciao-21234-a-12345.tgz: Questo dovrebbe darmi
FolderNamecomehello-21234-aeVersioncome12345
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
FolderNamecomehelloeVersioncome1234 - world-12345-stage.tgz: Questo dovrebbe darmi
FolderNamecomeworldeVersioncome12345 - ciao-21234-12345-prod.tgz: Questo dovrebbe darmi
FolderNamecomehello-21234eVersioncome12345 - ciao-21234-a-12345-prod.tgz: Questo dovrebbe darmi
FolderNameashello-21234-aeVersionas12345
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
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
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)
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
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+
È 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)