在Python中高效地合并两个大字符串

5

我已经在这方面工作了几天,似乎没有地方有我需要的答案。

为了避免被标记为重复,我将解释为什么其他问题对我没有用。

  • 任何关于Python DIFFLIB的答案都不能满足我的需求。(我下面描述更多) 它太慢了-除非有人给我一个好的优化提示(unified_diff模块),否则我将无法使用它。

  • 我尝试过研究如何将大字符串发送到期望文件的命令中,但是没有一种选项适合我。如果我能让它工作,我就可以使用此选项(还在下面描述)。

  • 只要它是真正解决我的问题的问题,我不介意被标记为重复-我已经爬取了几个网站,但还没有找到适合我的解决方案。

我想在Python中合并两个大字符串。每个字符串约为1.5KB。假设有两个字符串str1和str2,我只想返回合并后的字符串,即str1与str2的附加信息。我不想删除任何内容。

在大部分情况下,这些字符串将是相对相同的。大多数时候,它们将相似度达到90%。不同之处在于第二个字符串可能会添加新信息,我想将该信息捕获到原始字符串中。

因此。

str1 = "This is a very
        Long string and
        This is how it looks."

str2 = "This is a very
        This is my Example
        This is how it looks."

result = "This is a very
          Long string and
          This is my Example 
          This is how it looks." #Third line was added to str1

我解决这个问题的第一种方法是使用git diff。我在Windows系统上,执行了一个git diff命令,将字符串输出到临时文件中,然后立即删除这些文件。我创建的cmd函数将返回输出(一个合并的差异)作为字符串。然后,我对字符串进行后处理,以删除差异总是添加的标题。我能够通过更改输出指示符为空格来删除每行上的'+'和'-'(为了简单起见,我从我的代码中使用所有选项)。
#The f1and f2 text files are created here
#cmd is a function created by me, and it uses the os module to execute the command

output = cmd("git diff -U999999 -b --no-index f1.txt f2.txt")

#f1 and f2 text files are deleted here

我尝试了DiffLib,但速度太慢了。它需要大约8-10分钟才能生成一个差异文件输出。我使用了unified_diff模块,并将参数传递为字符串和列表。我甚至尝试过修改源代码,但改动并没有使其更快。
我还尝试直接将字符串传递给git diff或diff。然而,会出现错误,提示“Argument List too Long”。我甚至尝试将字符串发送到标准输出,并将其用作文件参数,但效果也不佳。
如果可以调整这些选项以满足我的目标,我都可以接受。显然,我的当前解决方案(上面的代码块)非常低效,如果可能的话,我不想继续创建和删除文本文件。

如果 strA 是 "A \n B \n C \n D" 而 strB 是 "A \n E \n F \f D",那么输出结果应该是什么呢?是 A B C E F D 还是 A B E C F D - alex
3
你尝试过使用https://github.com/google/diff-match-patch吗?我可以想象你的问题规模可能太大了。 - user2390182
可能是重复问题 https://dev59.com/oYPba4cB1Zd3GeqPnx_j - Serge
@schwobaseggl,你的建议很有用,我已经写了一个答案并接受了它,但如果你也写一个答案,我会接受你的。谢谢! - Double E
@DoubleE 一切都好 :D 谢谢 - user2390182
显示剩余7条评论
2个回答

1
如果你想自己动手解决问题-你可以将每一行逐次添加到某个列表中,轮流使用第一个字符串和第二个字符串:
list_1 = "A\nB\nC\nD".split()
list_2 = "A\nE\nF\nD".split()
output = []

for i in range(len(list_1)):
    output.append(list_1[i])
    output.append(list_2[i])

for o in output:
    print(o)

>> A
>> A
>> B
>> E
>> C
>> F
>> D
>> D

然后您需要从输出列表中删除重复项(不使用集合,因为集合会打乱顺序)。

from collections import OrderedDict

output = list(dict.fromkeys(output))

for o in output:
    print(o)

>> A
>> B
>> E
>> C
>> F
>> D

我能想到一些注意事项:

(保留HTML,不解释)
  1. If len(list_1) != len(list_2), you will need to account for that.

  2. It's not clear to me what "merge" means in this context. For instance, if:

    list_1 == ["A", "B", "A", "D", "A", "C", "A", "D", "A", "B", "B", "B"]
    list_2 == ["B", "A", "C", "C", "A", "A", "D", "D", "A", "B", "C", "A", "D"]
    

我不清楚合并后的结果应该是什么样子。


合并将是相对相同的。为了澄清,这些字符串来自我不想编辑,只想读取的文件。比如说- file1 和 file2。每个文件都包含信息块。大多数情况下,这些文件将是相同的。然而有时会添加一个或两个信息块。因此,在您的示例中,列表不会非常不同。它们只会在某个地方包含额外的行。是的,它们可能长度不同。我对字符串进行预处理,这样就无法直接使用 diff 文件。 - Double E

0

在@schwobaseggl的建议下,我找到了解决方案。

Diff_patch_match比difflib快得多。

对于任何遇到类似问题的人,以下是我遇到的一些障碍以及如何解决它们:

  • 创建diff_patch_match对象时,请确保将字符串作为参数传递。
  • 如果您的输入仅为单行,则不必担心我的下一个问题。但是,如果您的字符串有多行(由'\n'分隔),则必须遵循不同的协议。该网站链接here。但是,以防万一该网站关闭,我在下面提供Python代码。
def diff_lineMode(text1, text2):
  dmp = new diff_match_patch()
  a = dmp.diff_linesToChars_(text1, text2)
  lineText1 = a[0]
  lineText2 = a[1]
  lineArray = a[2]
  diffs = dmp.diff_main(lineText1, lineText2, false)
  dmp.diff_charsToLines_(diffs, lineArray)
  return diffs

感谢大家的评论和回答!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接