【问题标题】:Python split before a certain characterPython 在某个字符之前拆分
【发布时间】:2017-03-22 10:29:32
【问题描述】:

我有以下字符串:

BUCKET1:/dir1/dir2/BUCKET1:/dir3/dir4/BUCKET2:/dir5/dir6

我正在尝试以一种可以取回以下 dict / 其他数据结构的方式对其进行拆分:

BUCKET1 -> /dir1/dir2/, BUCKET1 -> /dir3/dir4/, BUCKET2 -> /dir5/dir6/

如果我只有一个桶,而不是多个桶,我可以以某种方式拆分它,如下所示:

res.split(res.split(':', 1)[0].replace('.', '').upper()) -> it's not perfect 

输入:ADRIAN:/dir1/dir11/DANIEL:/dir2/ADI_BUCKET:/dir3/CULEA:/dir4/ADRIAN:/dir5/ADRIAN:/dir6/

输出:[(ADRIAN, /dir1/dir11), (DANIEL, /dir2/), (CULEA, /dir3/), (ADRIAN, /dir5/), (ADRIAN, /dir6/)


根据 Wiktor Stribiżew cmets,以下正则表达式可以完成这项工作:

 r"(BUCKET1|BUCKET2):(.*?)(?=(?:BUCKET1|BUCKET2)|$)"

【问题讨论】:

标签: python string split


【解决方案1】:

如果您有经验,我建议您按照其他人的建议学习 Regex。但是,如果您正在寻找替代方案,这里有一种不使用正则表达式的方法。它还会产生您正在寻找的输出。

string = input("Enter:") #Put your own input here.

tempList = string.replace("BUCKET",':').split(":")
outputList = []
for i in range(1,len(tempList)-1,2):
    someTuple = ("BUCKET"+tempList[i],tempList[i+1])
    outputList.append(someTuple)

print(outputList) #Put your own output here.

这将产生:

[('BUCKET1', '/dir1/dir2/'), ('BUCKET1', '/dir3/dir4/'), ('BUCKET2', '/dir5/dir6')]

如果您不熟悉 Regex,希望此代码更容易理解和操作,但如果您熟悉如何使用它,我仍然个人建议 Regex 来解决这个问题。

【讨论】:

    【解决方案2】:

    使用re.findall()函数:

    s = "ADRIAN:/dir1/dir11/DANIEL:/dir2/ADI_BUCKET:/dir3/CULEA:/dir4/ADRIAN:/dir5/ADRIAN:/dir6/"
    result = re.findall(r'(\w+):([^:]+\/)', s)
    
    print(result)
    

    输出:

    [('ADRIAN', '/dir1/dir11/'), ('DANIEL', '/dir2/'), ('ADI_BUCKET', '/dir3/'), ('CULEA', '/dir4/'), ('ADRIAN', '/dir5/'), ('ADRIAN', '/dir6/')]
    

    【讨论】:

    • 如果我有不同的名称而不是 BUCKET1、BUCKET2 等,例如:Adrian、Roman 等,该怎么办?我怎么能这样拆分它?
    • @AdrianDanielCulea,您应该为 keys 和值指定确切的规则。例如:键应以大写字母开头或仅包含大写字母,应由小写字母或其他字符组成。定义一些规则
    • 别忘了import re
    • 我无法控制这个。我所知道的是所有的桶(无论他们有什么名字)都在“:”之前,就是这样。我希望能够按“:”之前的任何内容进行拆分
    • @FelixBuechner,我永远不会忘记导入它。这是暗示的
    【解决方案3】:

    改用正则表达式?

    impore re
    test = 'BUCKET1:/dir1/dir2/BUCKET1:/dir3/dir4/BUCKET2:/dir5/dir6'
    
    output = re.findall(r'(?P<bucket>[A-Z0-9]+):(?P<path>[/a-z0-9]+)', test)
    print(output)
    

    这给了

    [('BUCKET1', '/dir1/dir2/'), ('BUCKET1', '/dir3/dir4/'), ('BUCKET2', '/dir5/dir6')]
    

    【讨论】:

    • 如果不是 BUCKET1、BUCKET2 等,我对这些存储桶有不同的名称,例如 Adrian、Ashish 等,我怎么能这样拆分呢?
    • 您必须修改[A-Z0-9]+ 部分才能正确捕获存储桶名称。您可以使用pythex.org 检查您的正则表达式。
    【解决方案4】:

    您似乎有一个预定义的“桶”列表,您想将其用作字符串内记录的边界。

    这意味着,匹配这些键值对的最简单方法是匹配其中一个存储桶,然后是一个冒号,然后是 任何不以与这些存储桶名称相等的字符序列开头的字符

    你可以使用

    r"(BUCKET1|BUCKET2):(.*?)(?=(?:BUCKET1|BUCKET2)|$)"
    

    如果您的值跨越多行,请使用 re.S / re.DOTALL 编译。请参阅regex demo

    详情

    • (BUCKET1|BUCKET2) - 捕获匹配并存储在 .group(1) 任何存储桶名称中的第一组
    • : - 冒号
    • (.*?) - 任何 0+ 个字符,尽可能少(因为 *? 是一个惰性量词),直到第一次出现(但不包括)...
    • (?=(?:BUCKET1|BUCKET2)|$) - 任何存储桶名称或字符串结尾。

    在转义存储桶名称时动态构建它(只是为了安全起见,以防这些名称包含 *+ 或其他特殊字符):

    import re
    buckets = ['BUCKET1','BUCKET2']
    rx = r"({0}):(.*?)(?=(?:{0})|$)".format("|".join([re.escape(bucket) for bucket in buckets]))
    print(rx)
    s = "BUCKET1:/dir1/dir2/BUCKET1:/dir3/dir4/BUCKET2:/dir5/dir6"
    print(re.findall(rx, s))
    # => (BUCKET1|BUCKET2):(.*?)(?=(?:BUCKET1|BUCKET2)|$)
         [('BUCKET1', '/dir1/dir2/'), ('BUCKET1', '/dir3/dir4/'), ('BUCKET2', '/dir5/dir6')]
    

    请参阅online Python demo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-06
      • 1970-01-01
      • 2018-01-23
      • 2017-11-02
      • 2021-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多