2017-09-02 2 views
2

j'ai ces mesures dans le documentregex pour obtenir des mesures

5.3 x 2.5 cm 
11 x 11 mm 
7 mm 
13 x 12 x 14 mm 
13x12cm 

Je dois extraire 5,3 x 2,5 cm en utilisant python utilisant l'expression rationnelle.

Jusqu'à présent, mon code est ci-dessous, mais il ne fonctionne pas correctement

x = "\.\d{1,2}|\d{1,4}\.?\d{0,2}|\d{5}\.?\d?|\d{6}\.?" 
by = "()?(by|x)()?" 
cm = "(mm|cm|millimeter|centimeter|millimeters|centimeters)" 
x_cm = "((" + x + " *(to|\-) *" + cm + ")" + "|(" + x + cm + "))" 
xy_cm = "((" + x + cm + by + x + cm + ")" +"|(" + x + by + x + cm + ")" +"|(" + x + by + x + "))" 
xyz_cm = "((" + x + cm + by + x + cm + by + x + cm + ")" + "|(" + x + by + x + by + x + cm + ")" + "|(" + x + by + x + by + x + "))" 
m = "((" + xyz_cm + ")" + "|(" + xy_cm + ")" + "|(" + x_cm + "))" 
a = re.compile(m) 
print a.findall(text) 

La sortie donne:

[('13', '13', '13', '13', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''), ('12', '12', '12', '12', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''), ('4', '4', '4', '4', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''), ('25', '25', '25', '25', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''), 
+2

Définir "ne fonctionne pas correctement": que fait-il * par rapport à ce qu'il * devrait * faire? Les exemples seraient les bienvenus. –

+0

Veuillez montrer et expliquer la différence entre la sortie que vous obtenez et la sortie que vous voulez. – Yunnosch

+1

Une chose que vous devez faire est de vous débarrasser des groupes de capture. Cependant, vous devriez vérifier le [modèle final] (https://regex101.com/r/LcTavz/1) après la concaténation, il seulement [renvoie des nombres seulement] (https://ideone.com/TOX9eK). –

Répondre

2

Les seuls problèmes avec la regex actuelle sont deux:

  • Vous devez vous débarrasser des groupes de capture depuis .findall extraira tous les sous-chaînes capturées plutôt que la valeur entière de correspondance (cependant, il est essentiel, vous pouvez aussi bien utiliser re.finditer et obtenir)
  • Le problème principal est que vous n'avez pas groupé le motif x, l'alternance du format numérique a ruiné la structure du motif final.

Une solution rapide ressemblera

x = "(?:\.\d{1,2}|\d{1,4}\.?\d{0,2}|\d{5}\.?\d?|\d{6}\.?)" 
by = "(?:)?(?:by|x)(?:)?" 
cm = "(?:mm|cm|millimeter|centimeter|millimeters|centimeters)" 
x_cm = "(?:" + x + " *(?:to|\-) *" + cm + "|" + x + cm + ")" 
xy_cm = "(?:" + x + cm + by + x + cm +"|" + x + by + x + cm +"|" + x + cm + by + x +"|" + x + by + x + ")" 
xyz_cm = "(?:" + x + cm + by + x + cm + by + x + cm + "|" + x + by + x + by + x + cm + "|" + x + by + x + by + x + ")" 
m = "{}|{}|{}".format(xyz_cm, xy_cm, x_cm) 

Voir la Python demo impression

['5.3 x 2.5', '11 x 11', '13 x 12 x 14', '13x12cm'] 

Pour améliorer encore il, penser à toutes les possibilités de x, by, cm et peut-être utiliser str.format à la place de concaténation.

3

Avec Regex, vous devez toujours construire lentement votre expression pour obtenir ce que vous voulez . Par exemple.

s = "5.3 x 2.5 cm" 

Vous souhaitez trouver les chiffres ici?

re.findall("\d+", s) 

vous donne tous les entiers:

["5", "3", "2", "5"] 

Ok, donc si vos chiffres peuvent être le point, mais ne flottaient pas besoin d'être. Ensuite, vous développez votre expression avec un groupe de correspondance non-capture qui a un point et peut-être quelques chiffres suivants.

re.findall("\d+(?:\.\d*)?", s) 

cela vous donne

["5.3", "2.5"] 

Ensuite, vous pouvez prendre la multiplication par un nombre arbitraire d'espaces autour de:

re.findall("(\d+(?:\.\d*)?)\s*x\s*(\d+(?:\.\d*)?)", s) 

Mettre les chiffres en groupes de match vous donne maintenant un tuple.

[("5.3", "2.5")] 

Vous pouvez ensuite continuer avec les unités:

re.findall("(\d+(?:\.\d*)?)\s*x\s*(\d+(?:\.\d*)?)\s*(cm|mm)", s) 

vous donnant le tuple que vous voulez:

[("5.3", "2.5", "cm")] 

et ainsi de suite.

Si vous construisez vos regexes comme ceci, vous avez une chance de voir ce que les pauses d'un changement à l'autre. Déboguer une énorme regex comme celle que vous avez posté ci-dessus est une tâche qui ne vaut pas la peine d'y aller.

Je ne nommerais pas mon unité regex comme cm qui est assez déroutant pour quiconque maintient votre code dans le futur. En dehors de cela, vous avez besoin d'exigences claires sur les formats numériques que vous voulez autoriser. Peut-être que quelqu'un introduira des notations scientifiques, etc. Vos regex deviendront très compliqués.

+0

Merci d'avoir résolu mon problème! Aussi merci pour toutes vos explications détaillées !!! – user1979556

+0

La seule chose qu'il ne trouve pas quand il n'y a qu'une seule mesure (7 mm) mais je vais le comprendre. – user1979556

+0

@ user1979556 Je pense que cela peut être laissé comme un exercice pour le lecteur ;-). – CodeMonkey