从右边开始每隔n个字符拆分字符串?

4

我有不同的非常大的文件集,我想将它们放在不同的子文件夹中。我已经为每个要使用的文件夹设置了一个连续的ID。

我想从右侧分割ID,以便在更深层次上始终有1000个文件夹。

示例:

id:100243 => 结果路径:'./100/243'

id:1234567890 => 结果路径:'1/234/567/890'

我找到了Split string every nth character?,但是所有解决方案都是从左到右的,而且我也不想为一行代码导入另一个模块。

我的当前(可工作)解决方案如下:

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))

输出结果为:/home/made/00/024/102/442 对于我想要做的简单事情,目前算法看起来笨拙而复杂。我想知道是否有更好的解决方案。如果没有,它可能会帮助其他人。
更新:
我真的很喜欢Joe Iddons的解决方案。使用.join和mod使它更快,更易读。
最终,我决定永远不想在前面加上“/”。为了摆脱前导的/(在len(s)%3为零的情况下),我改变了这一行。
'/'.join([s[max(0,i):i+3] for i in range(len(s)%3-3*(len(s)%3 != 0), len(s), 3)])

感谢你的大力帮助!

更新 2:

如果你要使用 os.path.join(就像在我之前的代码中一样),那么它会更加简单,因为 os.path.join 自己会处理参数的格式:

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))

将“最大ID长度”四舍五入到最接近n的倍数是否可接受?也就是说,如果第一个路径段始终为n个字符长,这样做可以吗? - Daniel Pryden
1
这里是一个起点... 将您提供的链接中的答案进行修改,改为 [line[i-n:i] for i in range(len(line), 0, -n)] 即可得到 ['890', '567', '234', ''] - turnip
@DanielPryden:那不是问题。 - SeparateReality
4个回答

3
您可以根据您所链接的答案进行调整,并利用mod的优美之处创建一个漂亮的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'

如果你想让它自动添加“点”(dot),就像你第一个例子所示:

s = '100243'

那么您可以像@MosesKoledoye建议的那样,使用or,而不是仅仅添加一个小三目运算符:

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

这种方法比提前反转字符串或反转list的方法更快。


你可以使用以下代码替换三元运算符:[s[0:len(s)%3] or '.'] - Moses Koledoye
@MosesKoledoye 非常好,绝对是的! - Joe Iddon

1

如果你已经解决了从左到右的方向问题,为什么不直接反转输入和输出呢?

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

输出:

'0987654321'

你可以使用你找到的从左到右的解决方案,然后只需要再次反转它即可。

谢谢!我认为这正是Serg Anuke在他上面的回答中所做的。 - SeparateReality

1
你可以使用正则表达式和取模运算符将字符串分成三组。以下解决方案应该能帮助你入门:
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]

输出:

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

1
这个解决方案应该能让你开始。我怀疑这点。相当难以理解。 - Moses Koledoye

1

试试这个:

>>> 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'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接