Próbuję podzielić dowolny ciąg numer, taki jak 3.1415926535897932384626433832795028841971 zaraz po każdym 0 lub grupa 0. Chciałbym jednak zachować 0 po każdej grupie.

Na przykład łańcuch 10203040506070809011 powinien zostać podzielony na

['10', '20', '30', '40', '50', '60', '70', '80', '90', '11']

A ciąg 3.1415926535897932384626433832795028841971 powinien zostać podzielony na

['3.14159265358979323846264338327950', '28841971']

Próbowałem podzielić ciąg z pozytywnym lookbehind i pustym sznurkiem:

import re
p = '(?<=0+)'

re.search(p, '102030405')
><_sre.SRE_Match object; span=(2, 2), match=''>

'102030405'.split(p)
>['102030405']

Ale to nie rozdziela ciąg w ogóle, nawet jeśli wzór jest dopasowany.

Próbowałem też dzielić rozdzielenie łańcucha na podstawie 0 i dodając 0 po pierwszych parach sznurków, ale wydaje się ona zawiła i nieefektywna.

l = '102030405'.split('0')
[e+'0' for e in l[:-1]] + [l[-1]]
>['10', '20', '30', '40', '5']

Czy jest jakiś sposób, aby podzielić ciąg w oparciu o lookhead lub lookBehind na pustym sznurku? Pytam o ogólne sprawy, a nie tylko z liczbami. Na przykład, jeśli chciałem podzielić od siebie 3:18am5:19pm10:28am do oddzielnych czasów bez utraty am lub pm i zdobądź tablicę ['3:18am', '5:19pm', '10:28am'], jak mógłbym iść o to ?

1
victor 24 czerwiec 2017, 00:05

3 odpowiedzi

Najlepsza odpowiedź

Ten prosty regex w re.findall powinien wystarczyć:

l = re.findall(r'[.1-9]+(?:0+|$)', s)

Uwaga:

  • findall Zwraca Wszystkie niezbyt nakładające się mecze wzoru w ciągu, jako listy ciągów.

  • Dla każdego meczu, chcemy najdłuższego ciągu cyfr (lub kropki) kończących się przynajmniej jednym zero lub końcem ciągu

  • Zer w końcu nie powinny być przechwytywane jako kolejny mecz (stąd (?:...)

Podobnie dla ciebie drugi przykład:

>>> re.findall(r'[\d:]+(?:am|pm|$)', '3:18am5:19pm10:28am')
['3:18am', '5:19pm', '10:28am']

Nie ma potrzeby Lookhead / LookBehind Magic, ani nie chciwego dopasowania.

0
randomir 23 czerwiec 2017, 21:36

Python split wymaga dopasowania o szerokości niezerowej.

Możesz użyć findall dzięki temu regex, aby uzyskać mecze:

>>> print re.findall(r'([\d.]+?(?:0+|$))', '10203040506070809011')
['10', '20', '30', '40', '50', '60', '70', '80', '90', '11']

>>> print re.findall(r'([\d.]+?(?:0+|$))', '3.1415926535897932384626433832795028841971')
['3.14159265358979323846264338327950', '28841971']

([\d.]+?(?:0|$)) pasuje do cyfry lub kropki, która kończy się 0 lub koniec linii.


Aktualizacja:

Jednak zanotuję jednak z edytowanego pytania i komentarzy, których szukasz ogólne rozwiązanie , aby użyć wzorców Regex zerowej szerokości do operacji podziału.

Proponuję zainstalować bardzo przydatne Moduł REGEX w Pythonie. Wersja 1 tego modułu zapewnia większość funkcji PCRE i daleko przewyższają domyślne moduł re.

Instalacja jest dość prosta. Wystarczy pobierz plik TAR GZIP z powyższego linku, a następnie uruchom:

sudo python setup.py install

Od wewnątrz katalogu dostajesz po wyodrębnianiu plików tar. (Ignoruj kilka ostrzeżeń w procesie instalacji).

Po zainstalowaniu regex wystarczy użyć tego kodu:

>>> import regex

>>> regex.DEFAULT_VERSION = regex.VERSION1

>>> regex.split(r'(?<=[ap]m)(?=.)', '3:18am5:19pm10:28am')
['3:18am', '5:19pm', '10:28am']

>>> print regex.split(r'(?<=0)(?=[1-9])', '10203040506070809011')
['10', '20', '30', '40', '50', '60', '70', '80', '90', '11']

>>> print regex.split(r'(?<=0)(?=[1-9])', '3.1415926535897932384626433832795028841971')
['3.14159265358979323846264338327950', '28841971']

>>> print regex.split(r'(?<=0)(?=[1-9])', '10020')
['100', '20']
1
anubhava 26 czerwiec 2017, 05:49

Użyj re.findall:

l = re.findall(r'(?<![^0])[1-9.]+0*', s)

Kluczem jest użycie podwójnej negacji: nie poprzedzony i nie jest to zero (pasujące do poprzedniego zera lub początku ciągu)

1
Casimir et Hippolyte 23 czerwiec 2017, 21:19