在字符串中枚举数字

2024-10-01 05:00:48 发布

您现在位置:Python中文网/ 问答频道 /正文

这似乎是一个问题,应该有一个相当直接的答案;可悲的是,我不是那么流利的Python,因为我还在学习,我还没有找到任何有助于谷歌。你知道吗

我的目标是根据字符串中已有的填充量来枚举该数字。我认为最好用一个例子来描述:

  • 0-file将从0-file枚举到9-file
  • 但是000-file将从000-file枚举到999-file。你知道吗

最终,我希望能够为[number][a-z][a-z][number][a-z][number].*这样做(因此file10name.so之类的东西不匹配),不过,我想我可以在以后用regex解决这部分问题。你知道吗

所以,问题归结为:

  • 如何获取文件中“padding”的长度?你知道吗
  • 如何确定这个数字在字符串中的位置,以便替换它?你知道吗
  • 如何在迭代时添加填充(我假设zfill,但我对是否有更好的方法感兴趣)。你知道吗

快速编辑:是的,psudo regex就是这样。它是为了传达这个概念,因此它为什么不匹配像“-”这样的东西。填充总是一个数字,不一定是0,但这没关系。到目前为止,这两个答案都是完美的。我能使它们适应我的需要。我已经处理完整的路径,但它的伟大有其他人看到这一点在未来。谢谢大家:)


Tags: 文件方法字符串答案number目标so数字
2条回答

这里是一个基于str.lstripstr.format的生成器实现。它将输入解析为标准字符串模板(例如'{0:02d}-file'),然后循环相应的值并使用该模板创建输出:

def process(s):
    zeros = len(s) - len(s.lstrip('0'))
    template = "{{0:0{0}d}}{1}".format(zeros, s.lstrip('0')) 
    for i in range(10**zeros):
        yield template.format(i)

用法示例:

>>> list(process('00-file'))
['00-file', '01-file', '02-file', ..., '98-file', '99-file']

它有以下限制:

  • 仅支持'0'填充;以及
  • 只支持引导填充

但是你可以把它调整到你自己的目的。你知道吗

在编写代码之前,您应该为要匹配的文件找出正确的规范。您为要匹配的文件名(“[number][a-z][a-z][number]”)提供的伪regexp甚至不包括您提供的示例,例如0-file。你知道吗

简单版本

但是,从表面上看,假设您也希望包含大写拉丁字母,下面是一个简单的函数,它将匹配[number][a-z][a-z][number],并返回适当的前缀、后缀和数字位数。你知道吗

import re

def find_number_in_filename(fn):
    m = re.match(r"(\d+)([A-Za-z]+)$", fn)
    if m:
        prefix, suffix, num_length = "", m.group(2), len(m.group(1))
        return prefix, suffix, num_length

    m = re.match(r"([A-Za-z]+)(\d+)$", fn)
    if m:
        prefix, suffix, num_length = m.group(1), "", len(m.group(2))
        return prefix, suffix, num_length

    return fn, "", 0

example_fn = ("000foo", "bar14", "baz0", "file10name")
for fn in example_fn:
    prefix, suffix, num_length = find_number_in_filename(fn)
    if num_length == 0:
        print "%s: does not match" % fn
    else:
        print "%s -> %s[%d-digits]%s" % (fn, prefix, num_length, suffix)

        all_numbered_versions = [("%s%0"+str(num_length)+"d%s") % (prefix, ii, suffix) for ii in range(0,10**num_length)]
        print "\t", all_numbered_versions[0], "through", all_numbered_versions[-1]

输出为:

000foo -> [3-digits]foo
    000foo through 999foo
bar14 -> bar[2-digits]
    bar00 through bar99
baz0 -> baz[1-digits]
    baz0 through baz9
file10name: does not match

注意,我正在使用标准的printf样式的字符串格式将数字转换为0填充的字符串,例如%03d表示0填充的3位数字。使用较新的^{}可能更适合于将来的校对。你知道吗

优雅地处理完整路径和扩展

如果您的输入包含完整路径和带有扩展名的文件名(例如/home/someone/project/foo000.txt),并且您只想基于路径的最后一段进行匹配,那么请使用os.path.split.splitext来执行此操作。你知道吗

更新:修复丢失的路径分隔符

import re
import os.path

def find_number_in_filename(path):
    # remove the path and the extension
    head, tail = os.path.split(path)
    head = os.path.join(head, "") # include / or \ on the end of head if it's missing
    fn, ext = os.path.splitext(tail)

    m = re.match(r"(\d+)([A-Za-z]+)$", fn)
    if m:
        prefix, suffix, num_length = head, m.group(2)+ext, len(m.group(1))
        return prefix, suffix, num_length

    m = re.match(r"([A-Za-z]+)(\d+)$", fn)
    if m:
        prefix, suffix, num_length = head+m.group(1), ext, len(m.group(2))
        return prefix, suffix, num_length

    return path, "", 0

example_paths = ("/tmp/bar14.so", "/home/someone/0000baz.txt", "/home/someone/baz00bar.zip")
for path in example_paths:
    prefix, suffix, num_length = find_number_in_filename(path)
    if num_length == 0:
        print "%s: does not match" % path
    else:
        print "%s -> %s[%d-digits]%s" % (path, prefix, num_length, suffix)

        all_numbered_versions = [("%s%0"+str(num_length)+"d%s") % (prefix, ii, suffix) for ii in range(0,10**num_length)]
        print "\t", all_numbered_versions[0], "through", all_numbered_versions[-1]

相关问题 更多 >