6
votes

Numéro séparé de l'unité dans une corde en python

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


1 commentaires

Vous constaterez peut-être que votre chemin est plus rapide que l'approche Regex, en particulier pour les chaînes courtes que vous utilisez.


12 Réponses :


7
votes

Vous pouvez utiliser une expression régulière pour diviser la chaîne en groupes: xxx


1 commentaires

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é.



0
votes

Que diriez-vous d'utiliser une expression régulière

http://python.org/doc/1.6/lib/Module -regsub.html


0 commentaires

2
votes

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))


0 commentaires

3
votes

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), '')


0 commentaires

0
votes

Pour cette tâche, j'utiliserais certainement une expression régulière: xxx

dans le modèle RE, \ s signifie "blancspace", \ d signifie "chiffre", \ s signifie non-blanc; * signifie "0 ou plus de la précédente", + 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 () Appelez sur l'objet de match. ( Thematch 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).


0 commentaires

0
votes

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")


1 commentaires

Vous avez besoin de re.match (r '\ s * (? p [- +]? [. 0-9] *) \ s * (? p . *)', S). Son manquant * après [0,0-9]



2
votes
s='17GB'
for i,c in enumerate(s):
    if not c.isdigit():
        break
number=int(s[:i])
unit=s[i:]

2 commentaires

-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.



10
votes

Vous pouvez sortir de la boucle lorsque vous trouverez le premier caractère non chiffre xxx pré>

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()


2 commentaires

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 + ''):



2
votes
>>> s="17GB"
>>> ind=map(str.isalpha,s).index(True)
>>> num,suffix=s[:ind],s[ind:]
>>> print num+":"+suffix
17:GB

0 commentaires

2
votes

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()


0 commentaires

0
votes

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 xxx


0 commentaires

0
votes

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


0 commentaires