合并两个几乎相同的字符串

2024-10-02 04:32:00 发布

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

我有两个对象,一个是带有(int, str)的元组列表,如下所示:

first_input = [
    (0  ,  "Lorem ipsum dolor sit amet, consectetur"),
    (1  ,  " adipiscing elit"),
    (0  ,  ". In pellentesque\npharetra ex, at varius sem suscipit ac. "),
    (-1 ,  "Suspendisse luctus\ncondimentum velit a laoreet. "),
    (0  ,  "Donec dolor urna, tempus sed nulla vitae, dignissim varius neque.")
]
# Note that the strings contain newlines `\n` on purpose.

另一个对象是字符串,它是一系列操作(*)的结果,通过设计,这些操作将导致上面所有字符串的串联,但会插入一些额外的换行符\n

(*:显然,在保存list of tuples结构时无法做到这一点)

例如:

second_input = "Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit. In pellentesque\npharetra ex, at varius sem\nsuscipit ac. Suspendisse luctus\ncondimentum velit a laoreet. Donec dolor urna, tempus sed\nnulla vitae, dignissim varius neque."
# Note that there are 3 new newlines,  here ^ for instance
# but also in "sem\nsuscipit" and "sed\nnulla"

我的目标是回到第一个结构,但保留额外的换行符。在我的例子中,我会得到:

expected_output = [
    (0  ,  "Lorem ipsum dolor sit amet,\nconsectetur"),  # new newline here
    (1  ,  " adipiscing elit"),
    (0  ,  ". In pellentesque\npharetra ex, at varius sem\nsuscipit ac. "), # new newline here
    (-1 ,  "Suspendisse luctus\ncondimentum velit a laoreet. "),
    (0  ,  "Donec dolor urna, tempus sed\nnulla vitae, dignissim varius neque.") # new newline here
]

除了通过逐个字符的比较来重建字符串之外,您还有其他聪明的方法吗

(注意:如果一个新的\n处于字符串的极限,我不在乎它在两个元组中的哪一个结束。例如,获取[(0, "foo\n"), (1, "bar")][(0, "foo"), (1, "\nbar")]并不重要。)


编辑:我想避免的是这样做:

position=0
output = []
for tup in first_input:
    reconstructed_string = ""
    for letter in tup[1]:
        if letter == second_input[position]:
            reconstructed_string = reconstructed_string + letter
        else:
            reconstructed_string = reconstructed_string + second_input[position]
        position +=1
    output.append((tup[0], reconstructed_string))
# Note: this is hastily written to give you an idea, I have no idea if it would work properly, probably not
# Well, it does seem to work without bug, at least in my example. That's unexpected lol. Anyway, if you can think of a better solution...!

也就是说,遍历字符串的每个字符并比较它们以逐个字符地重建字符串


Tags: 字符串innewinputstringherepositionsed
3条回答

我认为最简单的方法是将你在组合字符串上执行的任何操作转换回片段,但我想你已经想到了这一点。 相反,不能插入任何换行符,而是生成一个位置列表,在该列表中输入这些换行符。跟踪字符串位的长度,假设变量posis中存储了将“”替换为“\n”的位置,则可能如下所示:

 import numpy as np
 posis = [27,98187,227] # position of the newlines in your sample, length of full string as last entry
 lengths = [len(string) for _, string in first_input]
 covered_distance = 0 # lengths of all strings we looked at already                                           
 j = 0  # iterating index for positions                                                                       
 output = []                                                                     
 rel_pos = posis[0]-covered_distance # initialize relative position in the current string                    
 inserted_newlines = 0 # keep track of newlines we added already                  
 for i, [n, string] in enumerate(first_input):                                                                           
     while rel_pos < lengths[i]:                                                 
         string = string[:rel_pos+inserted_newlines]+'\n'\                       
                 +string[rel_pos+inserted_newlines+1:]  # replace the character at the relative position                         
         j += 1 # advance to the next newline to be inserted                              
         rel_pos = posis[j]-covered_distance # update the relative position                     
         inserted_newlines += 1  # keep track of inserted newlines      
     output.append((n, string))  # store resulting string               
     covered_distance += lengths[i]  # update the number of characters we passed                        
     rel_pos = posis[j]-covered_distance                                         

这不是很漂亮,但它适用于样本,为了进行适当的测试,我需要一些关于可能情况的更多信息,可能还有确定换行位置的操作

好的,考虑到没有字符被替换或修改(如OP所述),我可以得出以下结论:

first_input_no_newline = list(map(lambda x: (x[0], x[1].replace('\n', '')), first_input))

expected_output = []
for item in first_input_no_newline:
    next_index = len(item[1])

    second_input_copy = second_input
    offset = 0
    while True:
        amount = second_input_copy[:next_index].count("\n")
        if not amount:
            next_index += offset
            break
        offset += amount
        second_input_copy = second_input_copy.replace('\n', '', amount)

    expected_output.append((item[0], second_input[:next_index]))
    second_input = second_input[next_index:]

print(expected_output)

解释:你不必跟踪新线或类似的东西。此外,“first_input”中的换行符并不重要,因为我们在第二个输入中有所有换行符(加上更多换行符)

因此,只需获取first_input_no_newline的每个项目的长度,如果其中没有换行符,这也应该是second_input中的子字符串的长度,但是,如果有换行符,好的,只需继续计数并从第二个\u输入的副本中删除它们,并将此结果作为偏移量添加到原始第二个\u输入

输入示例(修复了OP的原始输入,在某些短语之间添加缺少的白色字符):

first_input = [
        (0, "Lorem ipsum dolor sit amet, consectetur"),
        (1, " adipiscing elit"),
        (0, ". In pellentesque\npharetra ex, at varius sem suscipit ac. "),
        (-1, "Suspendisse luctus\ncondimentum velit a laoreet. "),
        (0, "Donec dolor urna, tempus sed nulla vitae, dignissim varius neque.")
    ]

second_input = "Lorem ipsum dolor sit amet, \nconsectetur adipiscing elit. In pellentesque\npharetra ex, at varius sem \nsuscipit ac. Suspendisse luctus\ncondimentum velit a laoreet. Donec dolor urna, tempus sed \nnulla vitae, dignissim varius neque."

输出:

[
    (0, 'Lorem ipsum dolor sit amet, \nconsectetur'), 
    (1, ' adipiscing elit'), 
    (0, '. In pellentesque\npharetra ex, at varius sem \nsuscipit ac. '), 
    (-1, 'Suspendisse luctus\ncondimentum velit a laoreet. '), 
    (0, 'Donec dolor urna, tempus sed \nnulla vitae, dignissim varius neque.')
]

我会这样做——用糟糕的代码编写。我写得很匆忙

import re
first_input = [
(0  ,  "Lorem ipsum dolor sit amet, consectetur"),
    (1  ,  " adipiscing elit"),
    (0  ,  ". In pellentesque\npharetra ex, at varius sem suscipit ac. "),
    (-1 ,  "Suspendisse luctus\ncondimentum velit a laoreet. "),
    (0  ,  "Donec dolor urna, tempus sed nulla vitae, dignissim varius neque.")
]
second_input = "Lorem ipsum dolor sit amet,\n consectetur adipiscing elit. In pellentesque\npharetra ex, at varius sem\n suscipit ac. Suspendisse luctus\ncondimentum velit a laoreet. Donec dolor urna, tempus sed\n nulla vitae, dignissim varius neque."

first_sanitized = [x[1].replace('\n', '') for x in first_input]
second_sanitized = second_input.replace('\n', '')
newline_positions = [m.start() for m in re.finditer('\n' ,second_input, re.M)]
new_output = []
i = 0
print(second_sanitized)
newlines_so_far = 0
for first_str in first_sanitized:
   print(first_str)
   index = second_sanitized.index(first_str)
   number_of_newlines_in_between = sum([1 for x in newline_positions if (x > index and x < index + len(first_input[i][1]))])
   new_string = second_input[index : (index + len(first_input[i][1]) + number_of_newlines_in_between + newlines_so_far)]
   newlines_so_far += number_of_newlines_in_between
   new_element = (first_input[i][0], new_string)
   new_output.append(new_element)
   i = i + 1

相关问题 更多 >

    热门问题