1

我有一个用于分析的日志文件,因为那几行会重复它自己,但不是完全重复,比如说

Alex is here and Alex is here and we went out
We bothWe both went out

我想删除第一次出现并得到

Alex is here and we went out
We both went out

请分享一个在 Windows 中的 Vim 中执行的正则表达式。

4

3 回答 3

3

我不建议尝试使用正则表达式来解决这个问题。只需编写一个外部过滤器并使用它。

这是一个用 Python 编写的外部过滤器。您可以使用它来预处理日志文件,如下所示:

python prefix_chop.py logfile.txt > chopped.txt

但它也适用于标准输入:

cat logfile.txt | prefix_chop.py > chopped.txt

!这意味着您可以通过命令在 vim 中使用它。试试这些命令:转到第 1 行,然后通过外部程序从当前行到最后一行prefix_chop.py

1G
!Gprefix_chop.py<Enter>

或者您可以从 ex 模式执行此操作:

:1,$!prefix_chop.py<Enter>

这是程序:

#!/usr/bin/python

import sys
infile = sys.stdin if len(sys.argv) < 2 else open(sys.argv[1])

def repeated_prefix_chop(line):
    """
    Check line for a repeated prefix string.  If one is found,
    return the line with that string removed, else return the
    line unchanged.
    """
    # Repeated string cannot be more than half of the line.
    # So, start looking at mid-point of the line.
    i = len(line) // 2 + 1

    while True:
        # Look for longest prefix that is found in the string after pos 0.
        # The prefix starts at pos 0 and always matches itself, of course.
        pos = line.rfind(line[:i])
        if pos > 0:
            return line[pos:]
        i -= 1

        # Stop testing before we hit a length-1 prefix, in case a line
        # happens to start with a word like "oops" or a number like "77".
        if i < 2:
            return line

for line in infile:
    sys.stdout.write(repeated_prefix_chop(line))

#!在第一行添加了注释,因此如果您使用的是 Cygwin,它将在 Linux、Mac OS X 或 Windows 上作为独立程序运行。如果您只是在没有 Cygwin 的情况下使用 Windows,您可能需要制作一个批处理文件来运行它,或者只需键入整个命令python prefix_chop.py。如果您制作一个宏来运行它,您不必自己输入。

编辑:这个程序非常简单。也许它可以在“vimscript”中完成并纯粹在vim中运行。但是外部过滤器程序可以在 vim 之外使用......如果您愿意,您可以进行设置,以便日志文件每天通过过滤器运行一次。

于 2013-05-17T20:03:13.393 回答
1

正则表达式:\b(.*)\1\b

替换为:\1$1

如果你想处理两个以上的重复句子,你可以试试这个

\b(.+?\b)\1+\b
      --
       |->avoids matching individual characters in word like xxx

笔记

使用\<and\>代替\b

于 2013-05-17T16:54:08.607 回答
0

您可以通过在行的开头尽可能多地匹配,然后使用反向引用来匹配重复的位来做到这一点。

例如,此命令解决了您描述的问题:

:%s/^\(.*\)\(\1.*\)/\2
于 2013-05-17T16:25:45.160 回答