vim能否实现将一个文件的多处内容替换另一个文件的相应内容?

Vim、Emacs配置和使用
cao627
帖子: 992
注册时间: 2007-12-05 10:57
系统: ubuntu14.04
来自: 金山

vim能否实现将一个文件的多处内容替换另一个文件的相应内容?

#1

帖子 cao627 » 2012-03-15 21:27

比如文件1内容:
1
a1
其他
若干内容
2
a2
其他
若干内容
3
a3
其他
若干内容

比如文件2内容:
1
b1
其他
若干内容
2
b2
其他
若干内容
3
b3
其他
若干内容

如何实现将文件1的a1,a2,a3,......分别用文件2的b1,b2,b3,....替换。
头像
lilydjwg
论坛版主
帖子: 4258
注册时间: 2009-04-11 23:46
系统: Arch Linux
联系:

Re: vim能否实现将一个文件的多处内容替换另一个文件的相应内容?

#2

帖子 lilydjwg » 2012-03-15 22:01

录制宏,或者使用脚本语言。
aerofox
帖子: 1453
注册时间: 2008-05-24 8:30

Re: vim能否实现将一个文件的多处内容替换另一个文件的相应内容?

#3

帖子 aerofox » 2012-03-15 23:27

可以使用 paste 命令把这两个文件合并成一个文件,再 sed 或者 vim 的 :s 命令去掉多余的内容。
例如:

代码: 全选

paste 文件1 文件2 | sed '1~4s/\t.*//;2~4s/.*\t//;3~4s/\t.*//;4~4s/\t.*//' > 新文件
这里假定两个文件中都不含制表符。
头像
Fermat618
帖子: 728
注册时间: 2008-12-28 16:01

Re: vim能否实现将一个文件的多处内容替换另一个文件的相应内容?

#4

帖子 Fermat618 » 2012-03-16 15:57

用程序来做吧,先用个适合的数据结构把表示一下你的数据,后面就好弄了。
爱因斯坦会弹钢琴
爱因斯坦会拉小提琴
爱因斯坦会骑自行车
cao627
帖子: 992
注册时间: 2007-12-05 10:57
系统: ubuntu14.04
来自: 金山

Re: vim能否实现将一个文件的多处内容替换另一个文件的相应内容?

#5

帖子 cao627 » 2012-03-16 17:14

aerofox 写了:可以使用 paste 命令把这两个文件合并成一个文件,再 sed 或者 vim 的 :s 命令去掉多余的内容。
例如:

代码: 全选

paste 文件1 文件2 | sed '1~4s/\t.*//;2~4s/.*\t//;3~4s/\t.*//;4~4s/\t.*//' > 新文件
这里假定两个文件中都不含制表符。
谢谢,研究了一下这个命令
paste 文件1 文件2 是依次将文件1的每一行后加一制表符然后贴上文件2对应的行上的内容

所以在sed命令中第一行 第三行 第四行 执行s /\t.*// 删除制表符后的内容,第二行执行s/.*\t//删除字表符前的内容,
得到的效果就是:
用文件1的第一行做为新文件的第一行,文件2的第二行做为新文件的第二行,文件1的3,4行作为新文件的3,4行。

最巧妙的应该是1~4,2~4,3~4,4~4,这一组东东的使用。
它们功能照得到效果来看,应该是:
将全文的所有行以4行为一个循环单位,依次执行它们后面的s操作。

最后
除了 两个文件中都不含制表符 的要求外
还要满足 两个文件中的 “其他若干内容“所占的行数必须是固定且相等的。否者1~N这样的功能就不能应用了。


3楼!看到的话再问问:
如果:两个文件中的 “其他若干内容“所占的行数不是固定,且(行数)也不是对应相等的。
有办法吗?
头像
eexpress
帖子: 58428
注册时间: 2005-08-14 21:55
来自: 长沙

Re: vim能否实现将一个文件的多处内容替换另一个文件的相应内容?

#6

帖子 eexpress » 2012-03-16 17:32

特征是1,2,3这些数字行后面的一行,要替换?

我担心你只是说了一个特例,而不是规律。
● 鸣学
cao627
帖子: 992
注册时间: 2007-12-05 10:57
系统: ubuntu14.04
来自: 金山

Re: vim能否实现将一个文件的多处内容替换另一个文件的相应内容?

#7

帖子 cao627 » 2012-03-16 17:54

eexpress 写了:特征是1,2,3这些数字行后面的一行,要替换?

我担心你只是说了一个特例,而不是规律。
文件一 1,2,3,........下面的一行 替换为文件二 1 ,2,3,....下面的一行

1,2,3,.....单独占一行 在文件一和文件二中都是唯一的,而且也是依次递增的,即3这一行之后,出现的一个数独占一行的话,一定是4


这也应该算个规律吧。

所谓规律,无非能从局部推出全部
头像
eexpress
帖子: 58428
注册时间: 2005-08-14 21:55
来自: 长沙

Re: vim能否实现将一个文件的多处内容替换另一个文件的相应内容?

#8

帖子 eexpress » 2012-03-16 18:04

如果是这样的规律。脚本可以搞定。vim难。
● 鸣学
aerofox
帖子: 1453
注册时间: 2008-05-24 8:30

Re: vim能否实现将一个文件的多处内容替换另一个文件的相应内容?

#9

帖子 aerofox » 2012-03-16 19:00

代码: 全选

paste file1 file2 | sed '/^[[:digit:]]\+\t[[:digit:]]\+$/{s/\t.*//;N;s/\n.*\t/\n/}; s/\t.*//'
应该可以了吧?先不解释了,我看楼主应该自己能分析出来。
aerofox
帖子: 1453
注册时间: 2008-05-24 8:30

Re: vim能否实现将一个文件的多处内容替换另一个文件的相应内容?

#10

帖子 aerofox » 2012-03-16 19:23

刚才没注意行数不是对应相等,这样的话,上面的命令不行,得用更复杂的脚本编程,python 比较方便。
头像
rykka
帖子: 59
注册时间: 2011-06-24 9:14

Re: vim能否实现将一个文件的多处内容替换另一个文件的相应内容?

#11

帖子 rykka » 2012-03-16 22:38

能实现,但是最好还是写成函数

代码: 全选

function! s:replaceby(file,repeat,num)
    let b=readfile(a:file)
    for i in range(line('$'))
        if fmod(i,str2nr(a:repeat)) == a:num-1
            let line = b[i]
            " write line to current file
            exe (i+1)."put ='".line."'"
            exe (i+1)."del"
        endif
    endfor
endfunction
command! -nargs=* ReplaceBy call <SID>replaceby(<f-args>)
用法:
如果要用文件b中每4行的第2行...替换文件a中对应行数
在文件a中使用命令

代码: 全选

:ReplaceBy b 4 2
如果不是重复相同行数的话,
则用

代码: 全选

        if getline(i) =~ '^\d\+$'
来判断是否替换。
上次由 rykka 在 2012-03-16 22:51,总共编辑 1 次。
cao627
帖子: 992
注册时间: 2007-12-05 10:57
系统: ubuntu14.04
来自: 金山

Re: vim能否实现将一个文件的多处内容替换另一个文件的相应内容?

#12

帖子 cao627 » 2012-03-16 22:42

aerofox 写了:

代码: 全选

paste file1 file2 | sed '/^[[:digit:]]\+\t[[:digit:]]\+$/{s/\t.*//;N;s/\n.*\t/\n/}; s/\t.*//'
应该可以了吧?先不解释了,我看楼主应该自己能分析出来。
3楼你好 看到话帮忙看看

这条sed命令似乎可以最后一个分号做分界作这样理解:
分号前的部分做匹配和替换
然后再执行分号后的替换

但我执行

代码: 全选

paste a1 b1 | sed '/^[[:digit:]]\+\t[[:digit:]]\+$/{n;s/.*\t//};s/\t.*//'
发现所有数字行没有被;s/\t.*//'执行到
我的理解是/^[[:digit:]]\+\t[[:digit:]]\+$/匹配到数字行,接着根据前面得到的行做一个操作{n;s/.*\t//}
这个操作分两步 n 移到下行 接着做替换s/.*\t// 由于这两步是当作一个操作所以用了{}
然后;后面是新的操作 s/\t.*// 我的理解是这个操作是对分号前操作的到的全文结果重新行执行s/\t.*//操作,即相当于

代码: 全选

paste a1 b1 | sed '/^[[:digit:]]\+\t[[:digit:]]\+$/{n;s/.*\t//}' | sed 's/\t.*//'
但从执行结果来看这个理解好行不太对.这里能解释下吗
另外N 的解释网上看的不是很明白。
上次由 cao627 在 2012-03-16 23:29,总共编辑 2 次。
aerofox
帖子: 1453
注册时间: 2008-05-24 8:30

Re: vim能否实现将一个文件的多处内容替换另一个文件的相应内容?

#13

帖子 aerofox » 2012-03-16 22:50

经过试验,基本上用 vim 做到了,过程比较复杂,看看是否符合楼主的要求:

准备工作,不管用什么工具,从文件2中提取出要送给文件1的那些数据,并在最后加上一行随便什么数据(有一行就行),放到一个新文件中。用 sed 实现这一步的例子为:

代码: 全选

sed -n '/^[[:digit:]]\+$/{n;p};$p' file2 > tmpfile
用 vim 同时打开两个文件1 和 刚才生成的临时文件,在垂直分隔的两个窗口(只vim内部split出来的窗口)中编辑,文件1 位于左侧。

代码: 全选

vim -O file1 tmpfile
然后确保右侧编辑缓冲区中光标位于第一行,在激活左侧 file1 的情况下,执行下面这条 vim 命令

代码: 全选

:g/^\d\+$/+1 normal dd^Wlyyj^WhP
其中 ^W 代表 Ctrl-W,要用 Ctrl-V 加 Ctrl-W 输入。

解释:

代码: 全选

g/^\d\+$/+1
        全局查找只包含数字的行,每次找到后,将其下一行作为当前行,执行后面的命令
normal
        执行后面的 normal 模式操作
dd
        删除当前行
^Wl
        换到右侧窗口
yyj
        拷贝一行,光标下移,为下一次拷贝做准备。如果临时文件最后没有多余的一行,则最后一次j命令会失败。
^WhP
        换到左侧窗口后执行粘贴操作
cao627
帖子: 992
注册时间: 2007-12-05 10:57
系统: ubuntu14.04
来自: 金山

Re: vim能否实现将一个文件的多处内容替换另一个文件的相应内容?

#14

帖子 cao627 » 2012-03-16 23:23

谢谢,思路看懂了,琢磨一下。
aerofox
帖子: 1453
注册时间: 2008-05-24 8:30

Re: vim能否实现将一个文件的多处内容替换另一个文件的相应内容?

#15

帖子 aerofox » 2012-03-16 23:49

再来一个 sed 的版本,更简洁些:

代码: 全选

sed -f <( sed -n '/^[[:digit:]]\+/{s:.*:/^&$/{n;s/.*/:;N;s/\n//;s:$:/}:;p}' file2 ) file1
思路:
先根据 file2 的内容生成一个 sed 脚本,再用这个脚本来修改 file1。从 file2 生成的 sed 脚本是这个样子:

代码: 全选

/^1$/{n;s/.*/b1/}
/^2$/{n;s/.*/b2/}
/^3$/{n;s/.*/b3/}
如果 b1、b2、b3 等地方会有 &、\L 等对 sed 脚本 s 命令来说有特别含义的内容时,这种做法会出问题。
回复