web-dev-qa-db-fra.com

Fractionner la chaîne à la nième occurrence d'un caractère donné

Existe-t-il une méthode Python pour diviser une chaîne après la nième occurrence d'un délimiteur donné?

Étant donné une chaîne:

'20_231_myString_234'

Il doit être divisé en (avec le délimiteur étant '_', après sa deuxième occurrence):

['20_231', 'myString_234']

Ou est-ce la seule façon d'accomplir cela pour compter, diviser et rejoindre?

37
cherrun
>>> n = 2
>>> groups = text.split('_')
>>> '_'.join(groups[:n]), '_'.join(groups[n:])
('20_231', 'myString_234')

On dirait que c'est la façon la plus lisible, l'alternative est regex)

57
jamylak

Utiliser re pour obtenir une expression régulière de la forme ^((?:[^_]*_){n-1}[^_]*)_(.*)n est une variable:

n=2
s='20_231_myString_234'
m=re.match(r'^((?:[^_]*_){%d}[^_]*)_(.*)' % (n-1), s)
if m: print m.groups()

ou avoir une fonction sympa:

import re
def nthofchar(s, c, n):
    regex=r'^((?:[^%c]*%c){%d}[^%c]*)%c(.*)' % (c,c,n-1,c,c)
    l = ()
    m = re.match(regex, s)
    if m: l = m.groups()
    return l

s='20_231_myString_234'
print nthofchar(s, '_', 2)

Ou sans regex, en utilisant la recherche itérative:

def nth_split(s, delim, n): 
    p, c = -1, 0
    while c < n:  
        p = s.index(delim, p + 1)
        c += 1
    return s[:p], s[p + 1:] 

s1, s2 = nth_split('20_231_myString_234', '_', 2)
print s1, ":", s2
7
perreal

J'aime cette solution car elle fonctionne sans regex réelle et peut facilement être adaptée à un autre "nième" ou délimiteur.

import re

string = "20_231_myString_234"
occur = 2  # on which occourence you want to split

indices = [x.start() for x in re.finditer("_", string)]
part1 = string[0:indices[occur-1]]
part2 = string[indices[occur-1]+1:]

print (part1, ' ', part2)
5
pypat

Je pensais que je contribuerais mes deux cents. Le deuxième paramètre de split() vous permet de limiter le fractionnement après un certain nombre de chaînes:

def split_at(s, delim, n):
    r = s.split(delim, n)[n]
    return s[:-len(r)-len(delim)], r

Sur ma machine, les deux bonnes réponses de @perreal, la recherche itérative et les expressions régulières, mesurent en fait 1,4 et 1,6 fois plus lentement (respectivement) que cette méthode.

Il convient de noter que cela peut devenir encore plus rapide si vous n'avez pas besoin du bit initial. Ensuite, le code devient:

def remove_head_parts(s, delim, n):
    return s.split(delim, n)[n]

Je ne suis pas sûr de la dénomination, je l'avoue, mais ça fait l'affaire. De façon assez surprenante, elle est 2 fois plus rapide que la recherche itérative et 3 fois plus rapide que les expressions régulières.

J'ai mis en place mon script de test en ligne . Vous êtes invités à examiner et à commenter.

2
Yuval

Cela dépend de votre modèle pour cette répartition. Parce que si les deux premiers éléments sont toujours des nombres par exemple, vous pouvez construire expression régulière et utiliser le module re . Il est également capable de diviser votre chaîne.

0
Manveru

J'avais une chaîne plus grande pour diviser le nième caractère, je me suis retrouvé avec le code suivant:

# Split every 6 spaces
n = 6
sep = ' '
n_split_groups = []

groups = err_str.split(sep)
while len(groups):
    n_split_groups.append(sep.join(groups[:n]))
    groups = groups[n:]

print n_split_groups

Merci @perreal!

0
AllBlackt
>>>import re
>>>str= '20_231_myString_234'

>>> occerence = [m.start() for m in re.finditer('_',str)]  # this will give you a list of '_' position
>>>occerence
[2, 6, 15]
>>>result = [str[:occerence[1]],str[occerence[1]+1:]] # [str[:6],str[7:]]
>>>result
['20_231', 'myString_234']
0
Nullify