Odpowiedzi:
Jeśli chcesz wyodrębnić tylko dodatnie liczby całkowite, spróbuj wykonać następujące czynności:
>>> str = "h3110 23 cat 444.4 rabbit 11 2 dog"
>>> [int(s) for s in str.split() if s.isdigit()]
[23, 11, 2]
Argumentowałbym, że jest to lepsze niż przykład wyrażenia regularnego z trzech powodów. Po pierwsze, nie potrzebujesz innego modułu; po drugie, jest bardziej czytelny, ponieważ nie trzeba analizować mini-języka regex; i po trzecie, jest szybszy (a więc prawdopodobnie bardziej pythoniczny):
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
To nie rozpoznaje liczb zmiennoprzecinkowych, ujemnych liczb całkowitych lub liczb całkowitych w formacie szesnastkowym. Jeśli nie możesz zaakceptować tych ograniczeń, poniższa odpowiedź Slim rozwiąże problem.
re
. Jest to ogólne i potężne narzędzie (dzięki czemu uczysz się czegoś bardzo przydatnego). Szybkość jest w pewnym stopniu nieistotna podczas analizowania dziennika (w końcu nie jest to intensywny solver numeryczny), re
moduł znajduje się w standardowej bibliotece Pythona i ładowanie go nie boli.
mumblejumble45mumblejumble
w których wiedziałem, że jest tylko jedna liczba. Rozwiązanie jest po prostu int(filter(str.isdigit, your_string))
.
str
która następnie przesłania str
obiekt i metodę w podstawowym pythonie. To nie jest dobra praktyka, ponieważ może być potrzebna później w skrypcie.
int(filter(...))
podniesie TypeError: int() argument must be a string...
dla Python 3.5, więc możesz użyć zaktualizowanej wersji: int(''.join(filter(str.isdigit, your_string)))
do wyodrębnienia wszystkich cyfr do jednej liczby całkowitej.
Użyłbym wyrażenia regularnego:
>>> import re
>>> re.findall(r'\d+', 'hello 42 I\'m a 32 string 30')
['42', '32', '30']
To również pasuje do 42 z bla42bla
. Jeśli chcesz tylko liczby rozdzielane granicami słów (spacja, kropka, przecinek), możesz użyć \ b:
>>> re.findall(r'\b\d+\b', 'he33llo 42 I\'m a 32 string 30')
['42', '32', '30']
Aby skończyć z listą liczb zamiast listy ciągów:
>>> [int(s) for s in re.findall(r'\b\d+\b', 'he33llo 42 I\'m a 32 string 30')]
[42, 32, 30]
int
go i gotowe. +1, szczególnie w drugiej części. Sugerowałbym jednak nieprzetworzone ciągi ( r'\b\d+\b' == '\\b\\d+\\b'
).
int_list = [int(s) for s in re.findall('\\d+', 'hello 12 hi 89')]
map
.
Jest to więcej niż trochę za późno, ale możesz rozszerzyć wyrażenie regularne, aby uwzględnić również zapis naukowy.
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)
Daje wszystko dobrze!
Dodatkowo możesz spojrzeć na regex wbudowanego kleju AWS
s = "4"
zwraca żadnych wyników. Czy można ponownie edytować, aby się tym zająć?
[+-]?\d*[\.]?\d*(?:(?:[eE])[+-]?\d+)?
grupa ta ma dać kilka fałszywych alarmów (tzn +
zostaje schwytany przez siebie czasami), ale jest w stanie obsłużyć więcej form, takich jak .001
, plus nie łączyć numery automatycznie (jak w s=2+1
)
[-+]?[.]?[\d]+(?:,\d\d\d)*[\.]?\d*(?:[eE][-+]?\d+)?
- tak głupie z mojej strony ... jak mogłem o tym nie myśleć?
Zakładam, że chcesz liczb zmiennoprzecinkowych nie tylko liczb całkowitych, więc zrobiłbym coś takiego:
l = []
for t in s.split():
try:
l.append(float(t))
except ValueError:
pass
Pamiętaj, że niektóre inne opublikowane tutaj rozwiązania nie działają z liczbami ujemnymi:
>>> re.findall(r'\b\d+\b', 'he33llo 42 I\'m a 32 string -30')
['42', '32', '30']
>>> '-3'.isdigit()
False
float
na int
.
re.findall("[-\d]+", "1 -2")
continue
zamiast pass
w pętli?
Jeśli wiesz, że będzie to tylko jedna liczba w ciągu, tzn. „Witaj 12 cześć”, możesz spróbować przefiltrować.
Na przykład:
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
Ale bądź ostrożny !!! :
In [4]: int(''.join(filter(str.isdigit, '200 grams 5')))
Out[4]: 2005
TypeError: int() argument must be a string, a bytes-like object or a number, not 'filter'
- naprawienie go za pomocąint("".join(filter(str.isdigit, '200 grams')))
# 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]
Używanie Regex poniżej jest sposobem
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)
z findall
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()
repl_str = re.compile('\d+.?\d*')
powinno być: repl_str = re.compile('\d+\.?\d*')
Dla odtwarzalnego przykładu z użyciem python3.7 re.search(re.compile(r'\d+.?\d*'), "42G").group()
'42G' re.search(re.compile(r'\d+\.?\d*'), "42G").group()
'42'
line2 = "hello 12 hi 89"
temp1 = re.findall(r'\d+', line2) # through regular expression
res2 = list(map(int, temp1))
print(res2)
Cześć ,
możesz przeszukiwać wszystkie liczby całkowite w ciągu poprzez cyfrę, używając wyrażenia findall.
W drugim kroku utwórz listę res2 i dodaj do niej cyfry znalezione w ciągu
mam nadzieję że to pomoże
Pozdrawiam, Diwakar Sharma
Ta odpowiedź zawiera także przypadek, gdy liczba jest zmiennoprzecinkowa w ciągu
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)
Dziwi mnie, że nikt jeszcze nie wspomniał o użyciu itertools.groupby
jako alternatywy do osiągnięcia tego celu.
Możesz użyć itertools.groupby()
wraz z str.isdigit()
, aby wyodrębnić liczby z łańcucha jako:
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]
Trzymana wartość l
będzie wynosić:
[12, 89]
PS: To jest wyłącznie w celu ilustracji, aby pokazać, że jako alternatywa moglibyśmy również groupby
to osiągnąć. Ale to nie jest zalecane rozwiązanie. Jeśli chcesz to osiągnąć, powinieneś użyć zaakceptowanej odpowiedzi fmark, opartej na używaniu rozumienia listy str.isdigit
jako filtra.
Właśnie dodam tę odpowiedź, ponieważ nikt nie dodał jej za pomocą obsługi wyjątków i ponieważ działa to również dla liczb zmiennoprzecinkowych
a = []
line = "abcd 1234 efgh 56.78 ij"
for word in line.split():
try:
a.append(float(word))
except ValueError:
pass
print(a)
Wynik :
[1234.0, 56.78]
Aby złapać różne wzorce, pomocne jest zapytanie o różne wzorce.
„[\ d] + [., \ d] +”
„[\ d] * [.] [\ d] +”
„[\ d] +”
(Uwaga: Najpierw umieść złożone wzory, w przeciwnym razie proste wzory zwrócą fragmenty złożonego połowu zamiast złożonego zwrotu zwracającego pełny połów).
p = '[\d]+[.,\d]+|[\d]*[.][\d]+|[\d]+'
Poniżej potwierdzimy obecność wzoru re.search()
, a następnie zwrócimy iterowalną listę połowów. Na koniec wydrukujemy każdy haczyk za pomocą notacji nawiasowej, aby podselektywnie zwrócić wartość obiektu dopasowania z obiektu dopasowania.
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
Zwroty:
33
42
32
30
444.4
12,001
Ponieważ żaden z nich nie dotyczył prawdziwych liczb finansowych w dokumentach Excel i Word, które musiałem znaleźć, oto moja odmiana. Obsługuje liczby całkowite, liczby zmiennoprzecinkowe, liczby ujemne, liczby walut (ponieważ nie odpowiada przy podziale) i ma opcję upuszczenia części dziesiętnej i po prostu zwraca liczby całkowite lub zwraca wszystko.
Obsługuje także system liczb Indian Laks, w którym przecinki pojawiają się nieregularnie, nie co 3 cyfry.
Nie obsługuje notacji naukowej ani liczb ujemnych umieszczonych w nawiasach w budżetach - będzie wyglądać na dodatnie.
Nie wyodrębnia również dat. Istnieją lepsze sposoby wyszukiwania dat w ciągach.
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
@jmnas, podobała mi się twoja odpowiedź, ale nie znalazłem pływaków. Pracuję nad skryptem do analizy kodu przechodzącego do frezarki CNC i potrzebowałem znaleźć zarówno X, jak i Y wymiary, które mogą być liczbami całkowitymi lub zmiennoprzecinkowymi, więc dostosowałem twój kod do następującego. Znajduje int, float z dodatnimi i ujemnymi vals. Nadal nie znajduje wartości w formacie szesnastkowym, ale możesz dodać „x” i „A” do „F” do num_char
krotki i myślę, że sparowałoby to rzeczy takie jak „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)
Najlepsza opcja, którą znalazłem, jest poniżej. Wyodrębni liczbę i może wyeliminować dowolny typ znaku.
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)
W przypadku numerów telefonów możesz po prostu wykluczyć wszystkie znaki inne niż cyfry z \ D w wyrażeniu regularnym:
import re
phone_number = '(619) 459-3635'
phone_number = re.sub(r"\D", "", phone_number)
print(phone_number)