J'ai des chaînes contenant des chiffres avec leurs unités, par exemple 2 Go, 17ft, etc. Je souhaite séparer le nombre de l'unité et créer 2 chaînes différentes. Parfois, il y a un espace entre eux (par exemple 2 Go) et il est facile de le faire en utilisant Split ('').
Quand ils sont ensemble (par exemple 2 Go), je testerais tous les personnages jusqu'à ce que je trouve une lettre, mais d'un nombre. P>
s='17GB' number='' unit='' for c in s: if c.isdigit(): number+=c else: unit+=c
12 Réponses :
Vous pouvez utiliser une expression régulière pour diviser la chaîne en groupes:
Pour correspondre à l'ensemble plus général de chiffres, y compris "6.2" et "3.4e-27" nécessiterait une regex beaucoup plus complexe. Trop de mauvais python n'a pas d'analogue de scanneau intégré.
Que diriez-vous d'utiliser une expression régulière p>
Vous devez utiliser des expressions régulières, regrouper ce que vous souhaitez découvrir:
import re s = "17GB" match = re.match(r"^([1-9][0-9]*)\s*(GB|MB|KB|B)$", s) if match: print "Number: %d, unit: %s" % (int(match.group(1)), match.group(2))
Tokenize code>
peut aider:
>>> import StringIO >>> s = StringIO.StringIO('27GB') >>> for token in tokenize.generate_tokens(s.readline): ... print token ... (2, '27', (1, 0), (1, 2), '27GB') (1, 'GB', (1, 2), (1, 4), '27GB') (0, '', (2, 0), (2, 0), '')
Pour cette tâche, j'utiliserais certainement une expression régulière: dans le modèle RE, \ s code> signifie "blancspace",
\ d code> signifie "chiffre",
\ s code> signifie non-blanc;
* code> signifie "0 ou plus de la précédente",
+ code> signifie "1 ou plus de la précédente, et les parenthèses entourent" des groupes de capture "qui sont ensuite renvoyés par le < Code> Groupes () Code> Appelez sur l'objet de match. (
Thematch CODE> NONE Si la chaîne donnée ne correspond pas au motif: Espace optionnel, puis à un ou plusieurs chiffres, puis en option. blanc, puis un ou plusieurs caractères non-blouses). P> P>
une expression régulière.
import re m = re.match(r'\s*(?P<n>[-+]?[.0-9])\s*(?P<u>.*)', s) if m is None: raise ValueError("not a number with units") number = m.group("n") unit = m.group("u")
Vous avez besoin de re.match (r '\ s * (? p
s='17GB' for i,c in enumerate(s): if not c.isdigit(): break number=int(s[:i]) unit=s[i:]
-1 s = '17 Go' donne une unité = 'GB', c'est-à-dire un espace devant l'unité. L'unité a besoin d'une lstrip, puis vous aurez la même réponse que la mienne.
Maintenant, j'ai relu la question, le cas de l'espace est traité avec une scission (), pas avec ce code. J'ai essayé de prendre le dos, mais ça ne me laisserait pas me laisser.
Vous pouvez sortir de la boucle lorsque vous trouverez le premier caractère non chiffre si vous avez négatif et des décimales: P> numeric = '0123456789-.'
for i,c in enumerate(s):
if c not in numeric:
break
number = s[:i]
unit = s[i:].lstrip()
Oui, cela fonctionne pour des entiers positifs. '-'. Isdigit () est aussi faux.
Le code ne donne pas de résultats incorrects lorsque l'unité est manquante. '10' -> Number = '1', unité = '0'. Pour résoudre ce problème, modifiez-le sur pour i, c en énumérable (s + ''): code>
>>> s="17GB" >>> ind=map(str.isalpha,s).index(True) >>> num,suffix=s[:ind],s[ind:] >>> print num+":"+suffix 17:GB
Ceci utilise une approche qui devrait être un peu plus pardonnant que les regextes. Remarque: Ceci n'est pas aussi performant que les autres solutions publiées.
def split_units(value): """ >>> split_units("2GB") (2.0, 'GB') >>> split_units("17 ft") (17.0, 'ft') >>> split_units(" 3.4e-27 frobnitzem ") (3.4e-27, 'frobnitzem') >>> split_units("9001") (9001.0, '') >>> split_units("spam sandwhiches") (0, 'spam sandwhiches') >>> split_units("") (0, '') """ units = "" number = 0 while value: try: number = float(value) break except ValueError: units = value[-1:] + units value = value[:-1] return number, units.strip()
Notation scientifique
Cette regex fonctionne bien pour moi pour analyser des chiffres pouvant être en notation scientifique et repose sur la récente documentation Python sur Scanf:
https://docs.python.org/3/library/re. HTML # simulant-scanf
Essayez le motif de regex ci-dessous. Le premier groupe (les jetons Scanf () pour un numéro quelconque) est soulevé directement à partir des documents Python pour le module RE.
import re SCANF_MEASUREMENT = re.compile( r'''( # group match like scanf() token %e, %E, %f, %g [-+]? # +/- or nothing for positive (\d+(\.\d*)?|\.\d+) # match numbers: 1, 1., 1.1, .1 ([eE][-+]?\d+)? # scientific notation: e(+/-)2 (*10^2) ) (\s*) # separator: white space or nothing ( # unit of measure: like GB. also works for no units \S*)''', re.VERBOSE) ''' :var SCANF_MEASUREMENT: regular expression object that will match a measurement **measurement** is the value of a quantity of something. most complicated example:: -666.6e-100 units ''' def parse_measurement(value_sep_units): measurement = re.match(SCANF_MEASUREMENT, value_sep_units) try: value = float(measurement[0]) except ValueError: print 'doesn't start with a number', value_sep_units units = measurement[5] return value, units
Vous constaterez peut-être que votre chemin est plus rapide que l'approche Regex, en particulier pour les chaînes courtes que vous utilisez.