27
votes

I can't figure out how to do this with string methods:

In my file I have something like 1.012345e0070.123414e-004-0.1234567891.21423... which means there is no delimiter between the numbers.

Now if I read a line from this file I get a string like above which I want to split after e.g. 12 characters. There is no way to do this with something like str.split() or any other string method as far as I've seen but maybe I'm overlooking something?

Thx

8
Funny: the answer I put here is almost verbatim the answer I put there... - Ned Batchelder

8 Answers

32
votes

Since you want to iterate in an unusual way, a generator is a good way to abstract that:

def chunks(s, n):
    """Produce `n`-character chunks from `s`."""
    for start in range(0, len(s), n):
        yield s[start:start+n]

nums = "1.012345e0070.123414e-004-0.1234567891.21423"
for chunk in chunks(nums, 12):
    print chunk

produces:

1.012345e007
0.123414e-00
4-0.12345678
91.21423

(which doesn't look right, but those are the 12-char chunks)

17
votes

You're looking for string slicing.

>>> x = "1.012345e0070.123414e-004-0.1234567891.21423"
>>> x[2:10]
'012345e0'
7
votes
line = "1.012345e0070.123414e-004-0.1234567891.21423"
firstNumber = line[:12]
restOfLine = line[12:]

print firstNumber
print restOfLine

Output:

1.012345e007
0.123414e-004-0.1234567891.21423
3
votes
from itertools import izip_longest

def grouper(n, iterable, padvalue=None):
    return izip_longest(*[iter(iterable)]*n, fillvalue=padvalue)
3
votes

you can do it like this:

step = 12
for i in range(0, len(string), 12):
    slice = string[i:step]
    step += 12

in this way on each iteration you will get one slice of 14 characters.

3
votes

I stumbled on this while looking for a solution for a similar problem - but in my case I wanted to split string into chunks of differing lengths. Eventually I solved it with RE

In [13]: import re

In [14]: random_val = '07eb8010e539e2621cb100e4f33a2ff9'

In [15]: dashmap=(8, 4, 4, 4, 12)

In [16]: re.findall(''.join('(\S{{{}}})'.format(l) for l in dashmap), random_val)
Out[16]: [('07eb8010', 'e539', 'e262', '1cb1', '00e4f33a2ff9')]

Bonus

For those who may find it interesting - I tried to create pseudo-random ID by specific rules, so this code is actually part of the following function

import re, time, random 
def random_id_from_time_hash(dashmap=(8, 4, 4, 4, 12)):
     random_val = ''
     while len(random_val) < sum(dashmap):
         random_val += '{:016x}'.format(hash(time.time() * random.randint(1, 1000)))
     return '-'.join(re.findall(''.join('(\S{{{}}})'.format(l) for l in dashmap), random_val)[0])
2
votes

Try this function:

x = "1.012345e0070.123414e-004-0.1234567891.21423"
while len(x)>0:
  v = x[:12]
  print v
  x = x[12:]
2
votes

I always thought, since string addition operation is possible by a simple logic, may be division should be like this. When divided by a number, it should split by that length. So may be this is what you are looking for.

class MyString:
    def __init__(self, string):
        self.string = string
    def __div__(self, div):
        l = []
        for i in range(0, len(self.string), div):
            l.append(self.string[i:i+div])
        return l

>>> m = MyString(s)
>>> m/3
['abc', 'bdb', 'fbf', 'bfb']


>>> m = MyString('abcd')
>>> m/3
['abc', 'd']

If you don't want to create an entirely new class, simply use this function that re-wraps the core of the above code,

>>> def string_divide(string, div):
       l = []
       for i in range(0, len(string), div):
           l.append(string[i:i+div])
       return l

>>> string_divide('abcdefghijklmnopqrstuvwxyz', 15)
['abcdefghijklmno', 'pqrstuvwxyz']