regex - Python:استخراج الأرقام من سلسلة




string numbers (10)

أود استخراج جميع الأرقام الموجودة في سلسلة. ما هو الأنسب للغرض أو التعبيرات العادية أو طريقة isdigit() ؟

مثال:

line = "hello 12 hi 89"

نتيجة:

[12, 89]

Answers

نظرًا لعدم معالجة أي من هذه الأرقام المالية في العالم الحقيقي في مستندات excel و word التي أحتاج إلى العثور عليها ، فإليك الشكل المختلف. فإنه يعالج النمل ، العوامات ، الأرقام السالبة ، أرقام العملات (لأنها لا ترد على انقسام) ، ولديها خيار إسقاط الجزء العشري وإرجاع النقط ، أو إرجاع كل شيء.

كما أنه يتعامل مع نظام رقم لاكنز الهندي حيث تظهر الفواصل بشكل غير منتظم ، وليس كل 3 أرقام منفصلة.

انها لا تتعامل مع التدوين العلمي أو الأرقام السلبية وضعت داخل الأقواس في الميزانيات - سوف تظهر إيجابية.

كما أنه لا يستخرج التواريخ. هناك طرق أفضل للبحث عن التواريخ في السلاسل.

import re
def find_numbers(string, ints=True):            
    numexp = re.compile(r'[-]?\d[\d,]*[\.]?[\d{2}]*') #optional - in front
    numbers = numexp.findall(string)    
    numbers = [x.replace(',','') for x in numbers]
    if ints is True:
        return [int(x.replace(',','').split('.')[0]) for x in numbers]            
    else:
        return numbers

أفضل خيار وجدته هو أدناه. وسوف استخراج عدد ويمكن القضاء على أي نوع من شار.

def extract_nbr(input_str):
    if input_str is None or input_str == '':
        return 0

    out_number = ''
    for ele in input_str:
        if ele.isdigit():
            out_number += ele
    return float(out_number)    

هذا أكثر من متأخر قليلاً ، ولكن يمكنك توسيع تعبير التعبير المعتاد لمراعاة الترميز العلمي أيضًا.

import re

# Format is [(<string>, <expected output>), ...]
ss = [("apple-12.34 ba33na fanc-14.23e-2yapple+45e5+67.56E+3",
       ['-12.34', '33', '-14.23e-2', '+45e5', '+67.56E+3']),
      ('hello X42 I\'m a Y-32.35 string Z30',
       ['42', '-32.35', '30']),
      ('he33llo 42 I\'m a 32 string -30', 
       ['33', '42', '32', '-30']),
      ('h3110 23 cat 444.4 rabbit 11 2 dog', 
       ['3110', '23', '444.4', '11', '2']),
      ('hello 12 hi 89', 
       ['12', '89']),
      ('4', 
       ['4']),
      ('I like 74,600 commas not,500', 
       ['74,600', '500']),
      ('I like bad math 1+2=.001', 
       ['1', '+2', '.001'])]

for s, r in ss:
    rr = re.findall("[-+]?[.]?[\d]+(?:,\d\d\d)*[\.]?\d*(?:[eE][-+]?\d+)?", s)
    if rr == r:
        print('GOOD')
    else:
        print('WRONG', rr, 'should be', r)

يعطي كل خير!

بالإضافة إلى ذلك ، يمكنك إلقاء نظرة على التضمين التوضيحي المدمج في AWS Glue


jmnas ، أعجبتني إجابتك ، لكنها لم تجد العوامات. أنا أعمل على برنامج نصي لتحليل رمز الذهاب إلى مطحنة التصنيع باستخدام الحاسب الآلي وتحتاج إلى العثور على كل من الأبعاد X و Y التي يمكن أن تكون أعدادًا صحيحة أو عائمة ، لذلك أعدلت شفرتك إلى ما يلي. هذا يجد int ، تطفو مع vals الإيجابية والسلبية. لا تزال لا تجد القيم المنسقة ست عشري ولكن يمكنك إضافة "س" و "أ" من خلال "F" إلى tuple num_char وأعتقد أنها ستحلل أشياء مثل "0x23AC".

s = 'hello X42 I\'m a Y-32.35 string Z30'
xy = ("X", "Y")
num_char = (".", "+", "-")

l = []

tokens = s.split()
for token in tokens:

    if token.startswith(xy):
        num = ""
        for char in token:
            # print(char)
            if char.isdigit() or (char in num_char):
                num = num + char

        try:
            l.append(float(num))
        except ValueError:
            pass

print(l)

# extract numbers from garbage string:
s = '12//n,[email protected]#$%3.14kjlw0xdadfackvj1.6e-19&*ghn334'
newstr = ''.join((ch if ch in '0123456789.-e' else ' ') for ch in s)
listOfNumbers = [float(i) for i in newstr.split()]
print(listOfNumbers)
[12.0, 3.14, 0.0, 1.6e-19, 334.0]

أنا مندهش لرؤية أي أحد ذكر حتى الآن استخدام itertools.groupby كبديل لتحقيق ذلك.

يمكنك استخدام itertools.groupby مع str.isdigit() لاستخراج الأرقام من السلسلة على النحو التالي:

from itertools import groupby
my_str = "hello 12 hi 89"

l = [int(''.join(i)) for is_digit, i in groupby(my_str, str.isdigit) if is_digit]

القيمة الممسوكة بواسطة l ستكون:

[12, 89]

ملاحظة: هذا فقط لغرض التوضيح لإظهار أنه كبديل يمكننا أيضا استخدام groupby لتحقيق ذلك. لكن هذا ليس حلا موصى به. إذا كنت ترغب في تحقيق ذلك ، فيجب أن تستخدم الإجابة المقبولة على fmark استنادًا إلى استخدام فهم القائمة باستخدام str.isdigit كفلتر.


أستخدم كلمة regexp:

>>> import re
>>> re.findall(r'\d+', 'hello 42 I\'m a 32 string 30')
['42', '32', '30']

هذا من شأنه أيضا أن يطابق 42 من bla42bla . إذا كنت تريد فقط تحديد الأرقام بواسطة حدود الكلمات (المسافة ، النقطة ، الفاصلة) ، فيمكنك استخدام \ b:

>>> re.findall(r'\b\d+\b', 'he33llo 42 I\'m a 32 string 30')
['42', '32', '30']

لتنتهي بقائمة الأرقام بدلاً من قائمة السلاسل:

>>> [int(s) for s in re.findall(r'\b\d+\b', 'he33llo 42 I\'m a 32 string 30')]
[42, 32, 30]

إذا كنت تريد استخراج أعداد صحيحة موجبة فقط ، فجرّب ما يلي:

>>> str = "h3110 23 cat 444.4 rabbit 11 2 dog"
>>> [int(s) for s in str.split() if s.isdigit()]
[23, 11, 2]

أنا أزعم أن هذا أفضل من مثال regex لثلاثة أسباب. أولا ، لا تحتاج إلى وحدة أخرى. ثانيًا ، يمكن قراءته بشكل أكبر لأنك لست بحاجة إلى تحليل اللغة البسيطة المعتادة ؛ وثالثًا ، إنها أسرع (ومن المحتمل أن تكون أكثر تتابعًا):

python -m timeit -s "str = 'h3110 23 cat 444.4 rabbit 11 2 dog' * 1000" "[s for s in str.split() if s.isdigit()]"
100 loops, best of 3: 2.84 msec per loop

python -m timeit -s "import re" "str = 'h3110 23 cat 444.4 rabbit 11 2 dog' * 1000" "re.findall('\\b\\d+\\b', str)"
100 loops, best of 3: 5.66 msec per loop

لن يتعرف هذا على العوامات أو الأعداد الصحيحة السالبة أو الأعداد الصحيحة بتنسيق سداسي عشري. إذا لم تتمكن من قبول هذه القيود ، فستكون الإجابة على الحل الصغير أدناه هي الخدعة.


تحتوي هذه الإجابة أيضًا على الحالة عندما يكون الرقم عائمًا في السلسلة

def get_first_nbr_from_str(input_str):
    '''
    :param input_str: strings that contains digit and words
    :return: the number extracted from the input_str
    demo:
    'ab324.23.123xyz': 324.23
    '.5abc44': 0.5
    '''
    if not input_str and not isinstance(input_str, str):
        return 0
    out_number = ''
    for ele in input_str:
        if (ele == '.' and '.' not in out_number) or ele.isdigit():
            out_number += ele
        elif out_number:
            break
    return float(out_number)

قد تجد في كثير من الأحيان

cond and on_true or on_false

ولكن هذا يؤدي إلى مشكلة عند on_true == 0

>>> x = 0
>>> print x == 0 and 0 or 1 
1
>>> x = 1
>>> print x == 0 and 0 or 1 
1

حيث تتوقع من المشغل الثلاثي العادي هذه النتيجة

>>> x = 0
>>> print 0 if x == 0 else 1 
0
>>> x = 1
>>> print 0 if x == 0 else 1 
1




python regex string numbers