【问题标题】:Python: Recursively split strings when longer than max allowed characters, by the last occurrence of a delimiter found before max allowed charactersPython:当长度超过允许的最大字符数时,通过在最大允许字符数之前找到的最后一次出现的定界符递归拆分字符串
【发布时间】:2023-01-23 22:50:44
【问题描述】:

我有一个对话的文本记录,由可变长度的字符串组成。字符串长度可以从几个字符到数千个字符不等。

我想让 Python 转换文本,使任何一行都最大化n人物。为了使分区自然,我想通过最后一次出现的分隔符 . , ? ! 对行进行递归分区。例如,假设以下 72 个字符的字符串超过 36 个字符的阈值:

这是一个很长很长的字符串。它大约(?)72 个字符!很酷

由于字符串的长度超过 36 个字符,因此该函数应按 36 个字符内最后一次出现的任何定界符递归地对字符串进行分区。递归意味着如果得到的分区字符串超过 36 个字符,它们也应该按照相同的规则进行拆分。在这种情况下,它应该产生如下列表:

['This, is a long, long string. ', 'It is around(?) 72 characters! ', 'Pretty cool']

列表项分别为30、31、11个字符。不允许超过 36 个字符。请注意,此示例中的分区不会出现在 , 分隔符处,因为它们不是 36+ 字符阈值内的最后一个分隔符。

分区顺序应该是这样的:

'This, is a long, long string. It is around(?) 72 characters! Pretty cool'           #  72
['This, is a long, long string. ', 'It is around(?) 72 characters! Pretty cool']     #  30 + 42
['This, is a long, long string. ', 'It is around(?) 72 characters! ', ' Pretty cool'] # 30 + 31 + 11

在字符串或递归分区中没有分隔符的奇怪情况下,应使用类似 textwrap.wrap() 的方式将字符串包装到最多 36 个字符,这会生成一个列表,在没有分隔符的情况下,该列表将是:

['There are no delimiters here so I am', ' partitioned at 36 characters] # 36 + 29

我试图制定出一个 Python 函数算法来实现这一点,但是这很困难。我在 ChatGPT 上花了很长时间,尽管有很多提示,但还是无法让它工作。

是否已经有一个 Python 模块函数可以实现这一点,或者您可以建议一个函数来解决这个问题?


我附上了下面的两个 ChatGPT 尝试以供参考,但不幸的是它们不起作用,因为如果该行超过 36 个字符的阈值,它将按每次出现的定界符而不是最接近的最后一个定界符拆分该行超过 36 个字符的限制。我无法解决这个问题,但提供了下面的代码,以防它给你任何想法。包含 MAX_COUNT 是为了防止无休止的递归循环,但我认为如果在没有分隔符的情况下添加 textwrap.wrap() 方法是多余的。

line = "This is a very long line of text that goes on and on and on and on. It contains a lot of words and sentences, and it is quite difficult to read. However, despite its length, it is still quite interesting and engaging! Or is it?"

import re

adjusted_lines = []

def split_line(line, count=0):
    split_lines = []
    MAX_COUNT = 1000
    if count < MAX_COUNT:
        if len(line) > 36:
            match = re.search(r'[.,?!](?=(.{0,31}\s))', line[::-1])
            if match:
                left = line[-match.start()-1:]
                right = line[:-match.start()-1]
                split_lines += [left] + split_line(right, count + 1)
            else:
                split_lines.append(line)
        else:
            split_lines.append(line)
    else:
        split_lines.append(line)
    return split_lines

adjusted_lines.extend(split_line(line))
print(adjusted_lines)

另一种尝试以同样的方式也是错误的:如果该行超过 36 个字符的阈值,它将根据每次出现的定界符而不是最接近 36+ 字符限制的最后一个定界符对该行进行分区:

line = "This is a very long line of text that goes on and on and on and on. It contains a lot of words and sentences, and it is quite difficult to read. However, despite its length, it is still quite interesting and engaging! Or is it?"

import textwrap

adjusted_lines = []

def partition_string(s):
    partitions = []
    if len(s) <= 36:
        partitions.append(s)
        return partitions
    index = -1
    delimiter = ""
    for d in [". ", ", ", "? ", "! "]:
        last_index = s.rfind(d)
        if last_index != -1:
            if last_index > index:
                index = last_index
                delimiter = d
    if index != -1:
        left_part = s[:index + len(delimiter)].rstrip()
        right_part = s[index + len(delimiter):]
        partitions.extend(partition_string(left_part))
        partitions.extend(partition_string(right_part))
    else:
        partitions.extend(textwrap.wrap(s, width=36))
    return partitions


adjusted_lines.extend(partition_string(line))
print(adjusted_lines)

注意:字数在线工具:https://www.charactercountonline.com/

【问题讨论】:

    标签: python string recursion split


    【解决方案1】:

    您可以使用 rfind 获取字符串的第一个 n 字符中最后一次出现的定界符。

    def partition(s, n):
        if len(s) <= n: return [s]
        idx = max(s.rfind(c, 0, n) for c in ['.', ',', '?', '!'])
        return [s] if idx == -1 else [s[0:idx+2], *partition(s[idx+2:], n)]
    print(partition('This, is a long, long string. It is around(?) 72 characters! Pretty cool', 36))
    

    【讨论】:

    • 会尝试!但它在* 上给出了语法错误。
    • @PAN 您使用的是什么版本的 Python?
    • 如果在较低版本的 Python 上,您可以将其替换为 [s[0:idx+2]] + partition(s[idx+2:], n)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-25
    相关资源
    最近更新 更多