La variable chaîne myvar peut avoir les valeurs suivantes:
mylar = "261.30 (NM) / 300.76 (MI) / 483.93 (KM)" int(myvar[28:-8])
J'ai besoin d'extraire les nombres 483.93 et 1.763.61 . Ces nombres doivent être convertis en nombres flottants ou arrondis aux nombres entiers.
Voici ce que j'ai essayé:
261.30 (NM) / 300.76 (MI) / 483.93 (KM) 952.27 (NM) / 1,096.09 (MI) / 1,763.61 (KM)
Cela fonctionne dans le premier cas ( 261,30 (NM) / 300,76 (MI) / 483,93 (KM) ). Mais il échoue en cas de 952.27 (NM) / 1.096.09 (MI) / 1.763.61 (KM) . Existe-t-il une solution générique?
7 Réponses :
Ce que je ferais dans ce cas est de créer une liste de valeurs, à partir de laquelle je peux extraire l'une d'entre elles.
myvar2 = myvar.replace("/", "").replace(",", "")
myvar2 = myvar2.split()
# This gives a list like this: ["261.30","(NM)","300.76","(MI)","483.93","(KM)"]
myfloat = float(myvar[4]) # This will return 483.93 on the first string and 1,763.61 on the second.
Vous pouvez le faire avec une expression régulière.
import re
target = '952.27 (NM) / 1,096.09 (MI) / 1,763.61 (KM)'
regex = r'.* \(NM\) \/ .* \(MI\) \/ (.*) \(KM\)'
res_str = re.findall(regex, target)
float_str = res_str[0].replace(',', '')
result = float(float_str)
À mon avis, le meilleur moyen est d'utiliser "([\., \ S \ d] +)". "(. *)" est trop général.
import re
m="261.30 (NM) / 300.76 (MI) / 483.93 (KM)"
print(float(re.split('\/',re.sub(',','',m))[2][:-5]))
Vous pouvez utiliser cette expression régulière qui détecte le dernier numéro de la chaîne et le place dans le groupe1,
Float value: 483.93 Int value: 483 Float value: 1763.61 Int value: 1763
Ensuite, avec le code python suivant, vous pouvez le convertir en float ou int. Je le convertis en float car ce sont des valeurs décimales, mais vous pouvez facilement les convertir en int.
import re
arr = ['261.30 (NM) / 300.76 (MI) / 483.93 (KM)','952.27 (NM) / 1,096.09 (MI) / 1,763.61 (KM)']
for s in arr:
val = re.search(r'([^ ]*)[^\d]*$', s)
floatval = float(re.sub(r',','',val.group(1)))
print('Float value: ' + str(floatval))
print('Int value: ' + str(int(floatval)))
Impressions,
([^ ]*)[^\d]*$
Puisque les valeurs sont suivies de (KM) , vous pouvez utiliser une anticipation positive:
483.93 1763.61
\ S + Correspond à 1+ caractères non blancs (? = \ (KM \)) Recherche positive pour vérifier ce qui se trouve à droite est un espace et (KM) Par exemple:
regex = r"\S+(?= \(KM\))"
strings = ["261.30 (NM) / 300.76 (MI) / 483.93 (KM)", "952.27 (NM) / 1,096.09 (MI) / 1,763.61 (KM)"]
for s in strings:
matches = re.search(regex, s)
if matches:
print(float(matches.group().replace(',', '')))
Cela vous donnera:
\S+(?= \(KM\))
Avec une seule fonction re.search , sans aucun remplacement:
1763.61
La sortie:
import re
myvar = '952.27 (NM) / 1,096.09 (MI) / 1,763.61 (KM)'
num = re.search(r'\/\s+(\d+),?(\d+\.\d+)\s+\(KM\)', myvar)
if num:
num = float(num.group(1) + num.group(2))
print(num)
p >
Cela ne fonctionnera pas si la valeur à capturer est comme 1 222 763,61 car elle ne gère pas plusieurs virgules dans la valeur, ce qui peut être le cas.
@PushpeshKumarRajwanshi: Bon à savoir. Merci. Mais dans mon cas, je n'aurai pas ces gros chiffres.
@ScalaBoy: C'est bien que vous n'ayez pas de valeurs contenant plusieurs virgules. Mais en général, je pense que vous devriez opter pour une approche plus générique qui fonctionne dans la plupart des cas, car votre code devient robuste. Sinon, si le code est maintenu plus tard par quelqu'un d'autre, vous ne serez identifié comme un bogue que lorsque les valeurs deviennent suffisamment grandes pour inclure plusieurs virgules. Même si je comprends que cela peut être un cas de courte durée pour vous où l'analyse de cette façon est plus que suffisante, donc tout va bien.
Vous pouvez également réaliser la même chose en utilisant uniquement split () str1="261.30 (NM) / 300.76 (MI) / 483.93 (KM)"
last_num_string=str1.split('/')[2].split('(')[0]
last_num_float=float(last_num_string)
print(last_num_float)
Avez-vous une expérience avec RegEx?
Mec, leurs longueurs sont différentes, bien sûr cela ne fonctionnera pas pour le deuxième cas. Et il a une virgule même entre les deux si vous optez même pour int (mylar [30: -8]) et il ne le convertira pas en chaîne. Utilisez simplement regex.
Merci pour les commentaires, les gars. J'ai peu d'expérience avec les regex. Je connais tous ces problèmes de mon code d'origine. Peut-être que je n'ai pas très bien expliqué, mais mon point était que le code est manifestement faux et j'ai demandé une solution correcte.