第一次出现在每一行vi / vim / sed等

时间:2012-06-13 19:53:36

标签: regex vim sed awk vi

使用VI替换第一个出现/实例非常简单。

    :%s/search/replace/args

但是,这是我的数据集.csv格式/文件:

"192.168.2.1","www.google.com","2009/01/11_10:00"," What a great website"
"192.168.2.2/driving/is/fun","-","2009/03/22_00:00","Driving website"
"192.168.2.4/boating/is/crazy","-","2009/03/22_00:00","Boating Website"
"192.168.2.5","www.cars.com","2009/04/27_00:00","What a good car website"

所以,你会注意到第一行有4列,这是.csv格式的理想行。

但是,在第二行中,有4列,但第一列只接受ip地址而已,只有192.168.2.2/driving/is/fun必须删除或用“,”.csv分隔符分隔

在vi中,我能够使用以下内容:

    :/^"\d\{,3}\.\d\{,3}\.\d\{,3}\.\d\{,3}\//s/\//","/

执行以下操作:

  • / ^“\ d {,3}。\ d {,3}。\ d {,3}。\ d {,3} / - 设置锚点以在第一个IP处开始搜索正斜杠/。例如,第2行:“192.168.2.2 /

  • / s ///“,”/ - 替换IP地址末尾的/并用.csv分隔符替换它“,”

这在VI / VIM中效果很好,一次取代我需要的一行。但是,数据集要大得多,并且使用以下vi搜索和替换手动操作非常耗时。我希望编写脚本或找到替代解决方案,因为VI / VIM一次只能执行一行,以下内容:s / search / replace / g替换每行/更改日期列的行。

显然,我尝试了以下方法:

在替换开头的内部添加整个文件的%,如下所示:

    :/^"\d\{,3}\.\d\{,3}\.\d\{,3}\.\d\{,3}\//%s/\//","/

突出显示我需要修改的每个条目,但错误输出:

    E492: Not an editor command: /^"\d\{,3}\.\d\{,3}\.\d\{,3}\.\d\{,3}\//%s/\//

这相当令人困惑。

我最终想用sed / perl编写一次编辑整个文件的脚本。

所以..

“192.168.2.2/ - >”192.168.2.2“,”

每一行都是第一次出现。

任何帮助将不胜感激..

谢谢!

3 个答案:

答案 0 :(得分:4)

在vi / vim中,您可以指定要替换的搜索范围。在这种情况下,您希望在所有行中替换:%s

:%s/search/replace/g

您还可以指定:

:2,5s/search/replace/g      Replace on lines 2-5
:.,$s/search/replace/g      Replace from current line (.) to last line ($)
:.,+3s/search/replace/g     Replace on the current line (.) and the two next lines (+3)
:g/^asd/s/search/replace/g  Replace on lines starting with 'asd'. 

然后,您可以将其与更简单的模式结合使用,以在整个文件中进行所需的替换:

:%s/^\("[^/"]*\)[^"]*"/\1"/

这将删除CSV中第一个条目的IP地址后的所有内容。

:%s/^\("[^/"]*\)\/\([^"]*\)"/\1","\2/

这会将第一个条目拆分为IP地址和其余部分,但这只会在IP之后有斜杠的行中完成。 你要做的是找到模式,转到那条线然后替换。在这种情况下添加'%'会使命令无效。

答案 1 :(得分:3)

在ViM中,尝试:

 :%s/^\("\d\{,3}\.\d\{,3}\.\d\{,3}\.\d\{,3}\)\(\/[^"]\)/\1","\2

也就是说,代替搜索/替代,我使用全局(%1,$的快捷方式,即从第一行到最后一行)替换。我将您的搜索模式移动到替换模式中,并在单独的组中捕获IP地址和路径。然后将它们替换回去,在它们之间挤压","

答案 2 :(得分:2)

你可以用更简单的模式做你想做的事:

s/^\("[^/"]*\)[^"]*"/\1"/

这是:匹配行首,开始匹配组:匹配",匹配任意数量不是斜杠且不是"的字符,关闭匹配组,匹配任意数量的字符不是",并且匹配"。替换为匹配组内容加上"

上述模式应该非常简单。这是一个Python示例。

#!/usr/bin/env python
import re
import sys

if len(sys.argv) != 3:
    print("Usage: log_file_cleaner <input_file> <output_file>")
    sys.exit(1)

pat = re.compile(r'^("[^/"]*)[^"]*"')

with open(sys.argv[1]) as in_f, open(sys.argv[2], "w") as out_f:
    for line in in_f:
        line = re.sub(pat, r'\1"', line)
        out_f.write(line)

注意:您需要最新版本的Python来执行一次with来执行两次open()次调用。如果你被困在Cygwin上,你可以将上面的内容编辑为两个嵌套with语句,每个语句都进行一次open()调用。