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

时间:2020-05-28 17:14:44

标签: python string merge

我有两个对象,一个是带有(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...!

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

3 个答案:

答案 0 :(得分:1)

我认为最简单的方法是将对组合字符串执行的所有操作转换回各个部分,但是我想您已经想到了这一点。 而是不能插入任何换行符,而是生成一个将要输入的位置列表。跟踪字符串位的长度,这看起来像这样,假设变量'{n'被替换为'\ n'的位置存储在变量posis中:

 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                                         

这不是很好,但是它适用于示例,为了进行适当的测试,我需要更多有关可能的情况以及确定换行位置的操作的信息。

答案 1 :(得分:0)

我会做的方式-用糟糕的代码编写。我很仓促地写了这个

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

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

答案 2 :(得分:0)

好吧,考虑到没有字符被替换或修改(如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中子字符串的长度,但是,如果有换行符,可以,只需继续计数并将它们从second_input的副本中删除,然后将此结果添加为偏移量即可剪切原始的second_input。

输入示例(固定了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.')
]

相关问题