Seite 1 von 1

String splitten...

Verfasst: Dienstag 31. Januar 2012, 18:40
von mutetella
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

Re: String splitten...

Verfasst: Dienstag 31. Januar 2012, 22:57
von needsch
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

Re: String splitten...

Verfasst: Mittwoch 1. Februar 2012, 01:22
von jerch
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.

Re: String splitten...

Verfasst: Mittwoch 1. Februar 2012, 08:33
von mutetella
@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