SeparateReality
SeparateReality

Reputation: 980

Split string every nth character from the right?

I have different very large sets of files which I'd like to put in different subfolders. I already have an consecutive ID for every folder I want to use. I want to split the ID from the right to always have 1000 folders in the deeper levels.

Example:

id: 100243 => resulting_path: './100/243'

id: 1234567890 => resulting path: '1/234/567/890'

I found Split string every nth character?, but all solutions are from left to right and I also did not want to import another module for one line of code.

My current (working) solution looks like this:

import os

base_path = '/home/made'
n=3    # take every 'n'th from the right
max_id = 12345678900
test_id = 24102442

# current algorithm
str_id = str(test_id).zfill(len(str(max_id)))
ext_path = list(reversed([str_id[max(i-n,0):i] for i in range(len(str_id),0,-n)]))
print(os.path.join(base_path, *ext_path))

Output is: /home/made/00/024/102/442

The current algorithm looks awkward and complicated for the simple thing I want to do. I wonder if there is a better solution. If not it might help others, anyway.

Update:

I really like Joe Iddons solution. Using .join and mod makes it faster and more readable.

In the end I decided that I never want to have a /in front. To get rid of the preceeding /in case len(s)%3is zero, I changed the line to

'/'.join([s[max(0,i):i+3] for i in range(len(s)%3-3*(len(s)%3 != 0), len(s), 3)])

Thank you for your great help!

Update 2:

If you are going to use os.path.join (like in my previous code) its even simpler since os.path.jointakes care of the format of the args itself:

ext_path = [s[0:len(s)%3]] + [s[i:i+3] for i in range(len(s)%3, len(s), 3)]
print(os.path.join('/home', *ext_path))

Upvotes: 4

Views: 1440

Answers (4)

Joe Iddon
Joe Iddon

Reputation: 20424

You can adapt the answer you linked, and use the beauty of mod to create a nice little one-liner:

>>> s = '1234567890'
>>> '/'.join([s[0:len(s)%3]] + [s[i:i+3] for i in range(len(s)%3, len(s), 3)])
'1/234/567/890'

and if you want this to auto-add the dot for the cases like your first example of:

s = '100243'

then you can just add a mini ternary use or as suggested by @MosesKoledoye:

>>> '/'.join(([s[0:len(s)%3] or '.']) + [s[i:i+3] for i in range(len(s)%3, len(s), 3)])
'./100/243'

This method will also be faster than reversing the string before hand or reversing a list.

Upvotes: 3

Serg Anuke
Serg Anuke

Reputation: 168

Try this:

>>> line = '1234567890'
>>> n = 3
>>> rev_line = line[::-1]
>>> out = [rev_line[i:i+n][::-1] for i in range(0, len(line), n)]
>>> ['890', '567', '234', '1']
>>> "/".join(reversed(out))
>>> '1/234/567/890'

Upvotes: 1

Ajax1234
Ajax1234

Reputation: 71461

You could use regex and modulo to split the strings into groups of three. This solution should get you started:

import re
s = [100243, 1234567890]
final_s = ['./'+'/'.join(re.findall('.{2}.', str(i))) if len(str(i))%3 == 0 else str(i)[:len(str(i))%3]+'/'+'/'.join(re.findall('.{2}.', str(i)[len(str(i))%3:])) for i in s]

Output:

['./100/243', '1/234/567/890']

Upvotes: 1

Mathieu
Mathieu

Reputation: 5746

Then if you got a solution for the direction left to right, why not simply reverse the input and output ?

str = '1234567890'
str[::-1]

Output:

'0987654321'

You can use the solution you found for left to right and then, you simply need to reverse it again.

Upvotes: 1

Related Questions