पायथन में एक स्ट्रिंग से संख्या कैसे निकालें?


432

मैं एक स्ट्रिंग में निहित सभी नंबरों को निकालूंगा। उद्देश्य, नियमित अभिव्यक्ति या isdigit()विधि के लिए बेहतर अनुकूल कौन सा है ?

उदाहरण:

line = "hello 12 hi 89"

परिणाम:

[12, 89]

जवाबों:


485

यदि आप केवल सकारात्मक पूर्णांक निकालना चाहते हैं, तो निम्न प्रयास करें:

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

मैं तर्क दूंगा कि यह तीन कारणों से रेगेक्स उदाहरण से बेहतर है। सबसे पहले, आपको दूसरे मॉड्यूल की आवश्यकता नहीं है; दूसरी बात, यह अधिक पठनीय है क्योंकि आपको रेगेक्स मिनी-भाषा को पार्स करने की आवश्यकता नहीं है; और तीसरा, यह तेज़ है (और इस तरह अधिक पाइथोनिक होने की संभावना है):

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

यह हेक्साडेसिमल प्रारूप में फ़्लोट्स, नकारात्मक पूर्णांक या पूर्णांक को नहीं पहचान सकेगा। यदि आप इन सीमाओं को स्वीकार नहीं कर सकते, तो नीचे दिया गया पतला उत्तर आपको कर देगा।


5
यह "h3110 23 बिल्ली 444.4 खरगोश 11-2 कुत्ते" जैसे मामले के लिए असफल हो जाएगा
शारफजफ्री

8
मानक मामले का उपयोग कर रहा है re। यह एक सामान्य और शक्तिशाली उपकरण है (ताकि आप कुछ बहुत उपयोगी सीखें)। लॉग पार्सिंग में गति कुछ हद तक अप्रासंगिक है (यह कुछ गहन संख्यात्मक सॉल्वर नहीं है), reमॉड्यूल मानक पायथन लाइब्रेरी में है और इसे लोड करने के लिए चोट नहीं लगती है।
Ioannis Filippidis

19
मेरे पास ऐसे तार mumblejumble45mumblejumbleथे जिनमें मुझे पता था कि केवल एक ही संख्या है। समाधान बस है int(filter(str.isdigit, your_string))
जोनास लिंडेलोव

1
एक मामूली टिप्पणी: आप चर को परिभाषित करते हैं strजो तब strआधार अजगर में ऑब्जेक्ट और विधि को ओवरराइड करता है । यह अच्छा अभ्यास नहीं है क्योंकि आपको बाद में स्क्रिप्ट में इसकी आवश्यकता हो सकती है।
जोनास लिंडेलोव

11
int(filter(...))TypeError: int() argument must be a string...पायथन 3.5 के लिए जुटाएगा , इसलिए आप अपडेट किए गए संस्करण का उपयोग कर सकते हैं: int(''.join(filter(str.isdigit, your_string)))सभी अंकों को एक पूर्णांक तक निकालने के लिए।
मार्क मिशिन

449

मैं एक 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]

9
... और फिर उस पर मैप करें intऔर आपका काम हो गया। +1 विशेष रूप से बाद वाले भाग के लिए। मैं r'\b\d+\b' == '\\b\\d+\\b'हालांकि कच्चे तार ( ) का सुझाव दूंगा ।

5
इसे जनरेटर के साथ एक सूची में रखा जा सकता है, जैसे:int_list = [int(s) for s in re.findall('\\d+', 'hello 12 hi 89')]
ग्रीनमैट

7
@GreenMatt: यह तकनीकी रूप से एक सूची समझ (जनरेटर नहीं) है, लेकिन मैं इस बात से सहमत हूं कि समझ / जनरेटर से अधिक पायथोनिक हैं map
सेठ जॉनसन

1
@ सेठ जॉनसन: उफ़! आप सही कह रहे हैं, मैं स्पष्ट रूप से मन की एक धूमिल अवस्था में था। :-( सुधार के लिए धन्यवाद!
ग्रीनमैट

2
हालांकि मुझे एक समस्या है। क्या होगा अगर मैं फ्लोट नंबरों को भी 1.45 की तरह "hello1.45 hi" में निकालना चाहता हूं। यह मुझे दो अलग-अलग संख्याओं के रूप में 1 और 45
देगा

89

यह थोड़ी देर से अधिक है, लेकिन आप वैज्ञानिक संकेतन के लिए भी रेगेक्स अभिव्यक्ति का विस्तार कर सकते हैं।

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 में निर्मित regex को देख सकते हैं


1
जैसा कि यह एकमात्र उत्तर है जिसे कोई पसंद करता है, यहां बताया गया है कि इसे वैज्ञानिक संकेतन के साथ कैसे किया जाए "[- +]? \ D + \ \।]? \ D * [Ee]? D d"। या कुछ भिन्नता। मज़े करो!
सहायतान.प्लान्ट.एम्काडॉनल्ड

पता लगाएं कि सबसे आसान मामला है जैसे s = "4"रिटर्न कोई मैच नहीं है। क्या इस बात का ध्यान रखने के लिए फिर से संपादन किया जा सकता है?
बैटफनर

1
अच्छा है, लेकिन यह कॉमा (जैसे
74,600

एक अधिक क्रिया समूह है [+-]?\d*[\.]?\d*(?:(?:[eE])[+-]?\d+)?यह समूह कुछ झूठी सकारात्मकता देता है (अर्थात +कभी-कभी खुद पर कब्जा कर लिया जाता है), लेकिन अधिक रूपों को संभालने में सक्षम है, जैसे .001, इसके अलावा यह संख्याओं को स्वचालित रूप से संयोजित नहीं करता है (जैसे s=2+1)
DavisDude

24
आह हाँ, स्पष्ट [-+]?[.]?[\d]+(?:,\d\d\d)*[\.]?\d*(?:[eE][-+]?\d+)?- तो मुझे मूर्ख ... मैं ऐसा कैसे नहीं सोच सकता था?
प्रेजेमेक डी

70

मैं मान रहा हूं कि आप केवल पूर्णांकों को नहीं तैरना चाहते हैं, तो मैं ऐसा कुछ करूंगा:

l = []
for t in s.split():
    try:
        l.append(float(t))
    except ValueError:
        pass

ध्यान दें कि यहां पोस्ट किए गए कुछ अन्य समाधान नकारात्मक संख्याओं के साथ काम नहीं करते हैं:

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

>>> '-3'.isdigit()
False

यह सकारात्मक और नकारात्मक फ्लोट और पूर्णांक पाता है। सिर्फ सकारात्मक और नकारात्मक पूर्णांकों, बदलाव के लिए floatकरने के लिए int
ह्यूगो

3
नकारात्मक संख्याओं के लिए:re.findall("[-\d]+", "1 -2")
ytpillai

अगर हम लूप continueकी जगह लिखते हैं तो क्या इससे कोई फ़र्क पड़ता है pass?
D. जोन्स

यह केवल धनात्मक पूर्णांक से अधिक पकड़ता है, लेकिन विभाजन का उपयोग करने से () संख्याओं में कमी आएगी, जिसमें मुद्रा के चिह्न पहले स्थान पर हैं, जिसमें कोई स्थान नहीं है, जो वित्तीय दस्तावेजों में सामान्य है
मार्क मैक्समिस्टर

फ्लोट्स के लिए काम नहीं करता है जिसमें अन्य वर्णों के साथ कोई स्थान नहीं है, उदाहरण: '4.5 k चीजें' काम करेंगी, '4.5k चीजें' नहीं होंगी।
जे। डी।

64

यदि आप जानते हैं कि यह स्ट्रिंग में केवल एक नंबर होगा, अर्थात 'हैलो 12 हाय', तो आप फ़िल्टर आज़मा सकते हैं।

उदाहरण के लिए:

In [1]: int(''.join(filter(str.isdigit, '200 grams')))
Out[1]: 200
In [2]: int(''.join(filter(str.isdigit, 'Counters: 55')))
Out[2]: 55
In [3]: int(''.join(filter(str.isdigit, 'more than 23 times')))
Out[3]: 23

लेकिन लापरवाह हो !!! :

In [4]: int(''.join(filter(str.isdigit, '200 grams 5')))
Out[4]: 2005

12
पायथन 3.6.3 में मुझे मिला TypeError: int() argument must be a string, a bytes-like object or a number, not 'filter'- इसका उपयोग करके इसे ठीक करनाint("".join(filter(str.isdigit, '200 grams')))
केंट मुन्थे कैस्परसन

16
# extract numbers from garbage string:
s = '12//n,_@#$%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]

3
उत्तर में आपका स्वागत है और उत्तर पोस्ट करने के लिए धन्यवाद। अपने उत्तर में कुछ अतिरिक्त टिप्पणियां जोड़ने के लिए हमेशा अच्छा अभ्यास करना और क्यों यह समस्या को हल करता है, बजाय केवल एक कोड स्निपेट पोस्ट करने के।
देखता है

मेरे मामले में काम नहीं किया। ऊपर दिए गए उत्तर से बहुत अलग नहीं है
Oldboy

ValueError: स्ट्रिंग को फ्लोट में नहीं बदल सकता: 'e' और यह कुछ मामलों में काम नहीं करता है :(
Vilq

15

मैं स्ट्रिंग्स के मुखौटे को हटाने के लिए एक समाधान की तलाश कर रहा था, विशेष रूप से ब्राजील के फोन नंबरों से, इस पोस्ट ने जवाब नहीं दिया लेकिन मुझे प्रेरित किया। यह मेरा समाधान है:

>>> phone_number = '+55(11)8715-9877'
>>> ''.join([n for n in phone_number if n.isdigit()])
'551187159877'

12

नीचे Regex का उपयोग करना तरीका है

lines = "hello 12 hi 89"
import re
output = []
#repl_str = re.compile('\d+.?\d*')
repl_str = re.compile('^\d+$')
#t = r'\d+.?\d*'
line = lines.split()
for word in line:
        match = re.search(repl_str, word)
        if match:
            output.append(float(match.group()))
print (output)

खोज के साथ re.findall(r'\d+', "hello 12 hi 89")

['12', '89']

re.findall(r'\b\d+\b', "hello 12 hi 89 33F AC 777")

 ['12', '89', '777']

यदि आप उपयोग नहीं कर रहे हैं, तो आपको कम से कम रीगेक्स को संकलित करना चाहिएfindall()
जानकारी

2
repl_str = re.compile('\d+.?\d*') होना चाहिए: repl_str = re.compile('\d+\.?\d*') python3.7 re.search(re.compile(r'\d+.?\d*'), "42G").group() '42G' re.search(re.compile(r'\d+\.?\d*'), "42G").group() '42' का उपयोग कर एक प्रतिलिपि प्रस्तुत करने योग्य उदाहरण के लिए
एलेक्सिस लुकाटिनी

8
line2 = "hello 12 hi 89"
temp1 = re.findall(r'\d+', line2) # through regular expression
res2 = list(map(int, temp1))
print(res2)

नमस्ते ,

आप खोज अभिव्यक्ति का उपयोग करके अंक के माध्यम से स्ट्रिंग में सभी पूर्णांक खोज सकते हैं।

दूसरे चरण में एक सूची res2 बनाएं और स्ट्रिंग में पाए गए अंकों को इस सूची में जोड़ें

उम्मीद है की यह मदद करेगा

सादर, दिवाकर शर्मा


प्रदान किए गए उत्तर को निम्न गुणवत्ता पोस्ट के रूप में समीक्षा के लिए चिह्नित किया गया था। यहाँ मैं कैसे एक अच्छा जवाब लिखने के लिए कुछ दिशानिर्देश हैं ? । यह प्रदान किया गया उत्तर सही हो सकता है, लेकिन यह एक स्पष्टीकरण से लाभान्वित हो सकता है। कोड केवल उत्तरों को "अच्छा" उत्तर नहीं माना जाता है। से समीक्षा
ट्रेंटन मैकिनी

सरल और काम कर रहे समाधान की सराहना की
मोयो

7

इस उत्तर में वह स्थिति भी होती है जब संख्या स्ट्रिंग में फ्लोट होती है

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)

5

मैं यह देखकर चकित हूं कि किसी ने भी 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इसे प्राप्त करने के लिए भी उपयोग कर सकते हैं । लेकिन यह अनुशंसित समाधान नहीं है। यदि आप इसे हासिल करना चाहते हैं, तो आपको फ़िल्टर के रूप में सूची की समझ का उपयोग करने के आधार पर स्वीकार किए जाते हैंstr.isdigit


4

मैं सिर्फ इस जवाब को जोड़ रहा हूं क्योंकि किसी ने अपवाद हैंडलिंग का उपयोग करके किसी को नहीं जोड़ा और क्योंकि यह फ्लोट के लिए भी काम करता है

a = []
line = "abcd 1234 efgh 56.78 ij"
for word in line.split():
    try:
        a.append(float(word))
    except ValueError:
        pass
print(a)

आउटपुट:

[1234.0, 56.78]

3

विभिन्न पैटर्न को पकड़ने के लिए विभिन्न पैटर्न के साथ क्वेरी करना सहायक होता है।

उन सभी पैटर्नों को सेट करें जो ब्याज के विभिन्न संख्या पैटर्न को पकड़ते हैं:

(कॉमा पाता है) 12,300 या 12,300.00

'[\ घ] [।, \ घ]'

(फ्लोट्स पाता है) 0.123 या .123

'[\ घ] * [।] [\ घ]'

(पूर्णांक पाता है) 123

'[\ घ]'

एकाधिक या सशर्त के साथ एक पैटर्न में पाइप (!) के साथ मिलाएं ।

(नोट: जटिल पैटर्न डालें और पहले सरल पैटर्न जटिल पकड़ को पूरा पकड़ने के बजाय जटिल पकड़ वापस कर देंगे)।

p = '[\d]+[.,\d]+|[\d]*[.][\d]+|[\d]+'

नीचे, हम पुष्टि करेंगे कि एक पैटर्न के साथ मौजूद है re.search(), फिर कैच की पुनरावृत्त सूची लौटाएं। अंत में, हम मैच ऑब्जेक्ट से वैल्यू रिटर्न वैल्यू को सब्स्क्राइब करने के लिए ब्रैकेट नोटेशन का उपयोग करके प्रत्येक कैच को प्रिंट करेंगे।

s = 'he33llo 42 I\'m a 32 string 30 444.4 12,001'

if re.search(p, s) is not None:
    for catch in re.finditer(p, s):
        print(catch[0]) # catch is a match object

यह दिखाता है:

33
42
32
30
444.4
12,001

2

चूंकि इनमें से कोई भी वास्तविक विश्व वित्तीय संख्या से एक्सेल और शब्द डॉक्स में निपटा नहीं है, जो मुझे खोजने की आवश्यकता है, यहां मेरी भिन्नता है। यह ints, floats, negative numbers, currency numbers (क्योंकि यह विभाजन पर उत्तर नहीं देता है) को संभालता है, और इसमें दशमलव भाग को छोड़ने और सिर्फ ints को वापस करने, या सब कुछ वापस करने का विकल्प होता है।

यह भारतीय Laks नंबर सिस्टम को भी संभालता है जहाँ अल्पविराम अनियमित रूप से दिखाई देते हैं, न कि प्रत्येक 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

1

@jmnas, मुझे आपका उत्तर पसंद आया, लेकिन यह फ्लोट नहीं मिला। मैं एक स्क्रिप्ट पर काम कर रहा हूँ जो कि एक सीएनसी मिल में जाने वाले कोड को पार्स करने के लिए है और एक्स और वाई दोनों आयामों को खोजने के लिए आवश्यक है जो पूर्णांक या फ्लोट हो सकते हैं, इसलिए मैंने आपके कोड को निम्नलिखित के लिए अनुकूलित किया। यह इंट, सकारात्मक और नकारात्मक वैल के साथ तैरता है। फिर भी हेक्स स्वरूपित मूल्यों को नहीं पाता है लेकिन आप "एक्स" और "ए" को "एफ" के माध्यम से 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)

0

मेरे द्वारा पाया गया सबसे अच्छा विकल्प नीचे है। यह एक नंबर निकालेगा और किसी भी प्रकार के चार को खत्म कर सकता है।

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)    

0

फ़ोन नंबरों के लिए आप regex में \ D के साथ सभी गैर-अंक वर्णों को बाहर कर सकते हैं:

import re

phone_number = '(619) 459-3635'
phone_number = re.sub(r"\D", "", phone_number)
print(phone_number)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.