String splitten...

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Hallo,

um einen string innerhalb eines bestimmten Bereiches auszugeben, möchte ich diesen string teilen. 'first' gibt die Länge der ersten, 'next_' die Länge der restlichen Zeilen an. 'lines' regelt die maximale Anzahl der insgesamt verfügbaren Zeilen.
Ein eventueller Rest von 'string_' wird ignoriert.

Ich habe das folgendermaßen gemacht, würde mich aber nicht wundern, wenn es schon eine bereits 'fertige' Lösung gäbe. Konnte aber in den Standardmodulen nix finden:

Code: Alles auswählen

def _split(string_, first, next_, lines):
    yield string_[:first]
    lines -= 1
    start = first
    stop = first + next_
    string_length = len(string_)
    while lines and not start >= string_length:
        yield string_[start:stop]
        start += next_
        stop += next_
        lines -= 1

Code: Alles auswählen

In [124]: string_ = '123456789X123456789x1234V'

In [125]: list(_split(string_, 3, 5, 4))
Out[125]: ['123', '45678', '9X123', '45678']

In [126]: list(_split(string_, 2, 4, 10))
Out[126]: ['12', '3456', '789X', '1234', '5678', '9x12', '34V']

In [127]: list(_split(string_, 5, 3, 10))
Out[127]: ['12345', '678', '9X1', '234', '567', '89x', '123', '4V']
Wie könnte man das noch lösen?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
needsch
User
Beiträge: 15
Registriert: Donnerstag 22. Dezember 2011, 21:28

Komisch, was du da vor hast. :-) Ich bin auch nicht so ganz mit dem Begriff "line" einverstanden.

So könnte man es noch machen (ist ein bisschen kompakter):

Code: Alles auswählen

from itertools import groupby
from math import ceil

def strange_split(data, first, next, count):
    yield data[:first]

    # Number of remaining parts.
    m = int(ceil((len(data)-first)/next))
    
    k = first
    for i in range(min(m, count-1)):
        yield data[k:k+next]
        k += next

def strange_split2(data, first, next, count):
    yield data[:first]
    rest = data[first:first+(count-1)*next]
    for group in groupby(enumerate(rest), lambda p: p[0] // next):
        yield "".join([char for index, char in group[1]])

print(list(strange_split("mein-supe", 5, 3, 4)))
print(list(strange_split("mein-super-", 5, 3, 4)))
print(list(strange_split("mein-super-to", 5, 3, 4)))
print(list(strange_split("mein-super-toller-string", 5, 3, 4)))
print(list(strange_split("mein-super-toller-string", 5, 3, 100)))
print()
print(list(strange_split2("mein-supe", 5, 3, 4)))
print(list(strange_split2("mein-super-", 5, 3, 4)))
print(list(strange_split2("mein-super-to", 5, 3, 4)))
print(list(strange_split2("mein-super-toller-string", 5, 3, 4)))
print(list(strange_split2("mein-super-toller-string", 5, 3, 100)))
Ausgabe:

Code: Alles auswählen

['mein-', 'sup', 'e']
['mein-', 'sup', 'er-']
['mein-', 'sup', 'er-', 'to']
['mein-', 'sup', 'er-', 'tol']
['mein-', 'sup', 'er-', 'tol', 'ler', '-st', 'rin', 'g']

['mein-', 'sup', 'e']
['mein-', 'sup', 'er-']
['mein-', 'sup', 'er-', 'to']
['mein-', 'sup', 'er-', 'tol']
['mein-', 'sup', 'er-', 'tol', 'ler', '-st', 'rin', 'g']
Die zweite Variante ist zwar nochmal kompakter, aber wg. Vergewaltigung der itertools ineffizient und schwer zu verstehen. Vielleicht schafft es ja jemand, das noch schöner zu implementieren.

Viele Grüße
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Schöner nicht, aber kompakter:

Code: Alles auswählen

f = lambda a,b,c,d:[a[:b]]+f(a[b:],0,c,d-1) if b else [a[:c]]+f(a[c:],0,c,d-1) if d>1 else [a[:c]]
:twisted:

Als Generator:

Code: Alles auswählen

lambda a,b,c,d:(a[:b] if not i else a[b+c*i-c:b+c*i] for i in xrange(d))
Beide enthalten mitunter leere Elemente am Ende, die lassen sich ja leicht mit filter() entsorgen.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@needsch:
Danke, Dein erstes Beispiel gefällt mir gut, allerdings hab' ich die Berechnung Deines 'm' (warum 'm'?) etwas verändert, weil:

Code: Alles auswählen

In [240]: #python2.6

In [241]: math.ceil(19 / 3)
Out[241]: 6.0

In [242]: math.ceil(19 / 3.0)
Out[242]: 7.0

In [243]: !python3
Python 3.1.2 (release31-maint, Dec  9 2011, 20:59:40) 
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import math
>>> math.ceil(19 / 3)
7
>>> 
Schaut demnach also jetzt so aus:

Code: Alles auswählen

def _split(string_, first, following, max_lines):
    yield string_[:first]
    remaining = int(ceil((len(string_) - first) / float(following)))
    start = first
    for i in xrange(min(remaining, max_lines - 1)):
        yield string_[start:start + following]
        start += following
@jerch:
Dein 'f' würde bei langen strings implodieren... ;-) Ok, bei seeeehr langen strings...


Danke für Eure Hilfe!

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Antworten