Chinaunix

标题: sed 段匹配 [打印本页]

作者: chzht001    时间: 2007-05-22 08:56
标题: sed 段匹配
有一个文本有若干段
我想删除符合以下特征的段:

1 第一种
title
fsdaf
fsdaf
空行(不删除本行)

2 第二种
title
fdsaf
fdsaf
#ded(不删除本行)

3 第三种
title
dsa
fdsf
文件结束

注: title前面可能有空格或制表符,只要符合以上特征之一的删除第一次匹配(匹配多次时)
     第一次匹配方式可能是第一种也可能是第二种,不一定,不要错误地理解为用第一种方式匹配的第一次删除
     再用第二种匹配的方式将匹配的第一次删除,而是将三种方式混合,是并集,只要匹配包含于该并集,就将第
     一次匹配删除,其余不作处理
     文件中还有其它种类的段或行,并不是只有title开头的段格式
想想都捏一把汗,不知能否用sed解

例如:
name  fdafds

# this is a file

title  mike
fdsaf
fdsaf
#ddasd

title jack
fdsf
fdsafa

处理后:
name  fdafds

# this is a file

#ddasd

title jack
fdsf
fdsafa

[ 本帖最后由 chzht001 于 2007-5-22 14:16 编辑 ]
作者: waker    时间: 2007-05-22 09:02
请注意发帖标题并读新手导航,谢谢
作者: Edengundam    时间: 2007-05-22 09:37
随便写了个, 貌似有些空行没有处理好...^^

  1. sed -n -r '
  2. :start
  3. /^title/{
  4. x;s:^\n::;s:\n?title$::;p;x;h;
  5. }
  6. n;
  7. /^$|^#/{
  8. x;s:.*::;x;P;
  9. b start;
  10. }
  11. H;
  12. b start;'
复制代码

作者: woodie    时间: 2007-05-22 11:27
写起来应该很简单,不过楼主的需求描述太混乱。^_^
作者: wdavid    时间: 2007-05-22 11:31
原帖由 woodie 于 2007-5-22 11:27 发表
写起来应该很简单,不过楼主的需求描述太混乱。^_^

同感。
作者: wdavid    时间: 2007-05-22 12:33
原帖由 woodie 于 2007-5-22 11:27 发表
写起来应该很简单,不过楼主的需求描述太混乱。^_^

同感。
作者: chzht001    时间: 2007-05-22 14:17
不知现在说的清不清楚,复杂的我都说不清了

可能这样描述会更清晰一点:
我们平常匹配段时会有如下的样子
匹配以title开头,以endtitle结尾的段
这种方式容易:
/^title/.../^endtitle/

但我现在的匹配方式是
匹配以title开头,以三种方式中的一种结尾的段
三种方式为:
空行
以#开头的行
文件尾

用sed如何描述呢?

不可以写三个表达式来做,那样会删除匹配三次,
而我只想删除,以这三种方式之一匹配的一次

以哪种方式匹配未知,但肯定是这三种中的一种,
可能有一种匹配,可能有两种匹配,也可能有三种匹配
无论第一次匹配是哪种,都将该次匹配删除,其余任何匹配无需再作处理

[ 本帖最后由 chzht001 于 2007-5-22 14:36 编辑 ]
作者: Edengundam    时间: 2007-05-22 15:04

  1. sed -n -r '
  2. /^title/{
  3. x;s:\n::;x;H;
  4. :read
  5. n;
  6. /^$|^#/{
  7. x;s:.*::;x;s:^\n::;p;
  8. b end;
  9. }
  10. /^title/{
  11. x;s:^\n::;p;s:.*::;x;H;
  12. b read;
  13. }
  14. H;
  15. b read;
  16. }
  17. p;
  18. :end'
复制代码


input file

  1. title
  2. fsdaf
  3. fsdaf

  4. title
  5. fdsaf
  6. fdsaf
  7. #ded

  8. title
  9. a
  10. b
  11. title
  12. c
  13. d
  14. title
  15. dsa
  16. fdsf

  17. 34213
  18. 43214
  19. 32
  20. 14
  21. 214

  22. title
  23. a
  24. b
  25. title
  26. c
  27. d
  28. title
  29. dsa
  30. fdsf
复制代码


result:


  1. #ded

  2. title
  3. a
  4. b
  5. title
  6. c
  7. d

  8. 34213
  9. 43214
  10. 32
  11. 14
  12. 214

  13. title
  14. a
  15. b
  16. title
  17. c
  18. d

复制代码

[ 本帖最后由 Edengundam 于 2007-5-22 15:15 编辑 ]
作者: woodie    时间: 2007-05-22 15:36
GNUsed 4.0.9,写的比较丑。^_^试试看:
sed '/title/,${0,/^$\|^#/{//p;d};}'
作者: woodie    时间: 2007-05-22 15:46
记忆中楼主的平台好像没有GNU工具,遗憾,那样的话楼上的代码就帮不上忙了。^_^
作者: chzht001    时间: 2007-05-22 15:47
原帖由 woodie 于 2007-5-22 15:36 发表
GNUsed 4.0.9,写的比较丑。^_^试试看:
sed '/title/,${0,/^$\|^#/{//p;d};}'


找不到GNUsed 4.0.9,我用GNUsed4.1.5

[sniff:/tmp] > cat bbb
title           aaaaa
fdsaf
        title   bbbbb
        fdaf
[sniff:/tmp] > sed '/title/,${0,/^$\|^#/{//p;d};}' bbb
[sniff:/tmp] > sed --version
GNU sed version 4.1.5
Copyright (C) 2003 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE,
to the extent permitted by law.
[sniff:/tmp] >
作者: chzht001    时间: 2007-05-22 15:50
原帖由 Edengundam 于 2007-5-22 15:04 发表

  1. sed -n -r '
  2. /^title/{
  3. x;s:\n::;x;H;
  4. :read
  5. n;
  6. /^$|^#/{
  7. x;s:.*::;x;s:^\n::;p;
  8. b end;
  9. }
  10. /^title/{
  11. x;s:^\n::;p;s:.*::;x;H;
  12. b read;
  13. }
  14. H;
  15. b read;
  16. }
  17. p;
  18. :end'
复制代码


input fil ...

[sniff:/tmp] > cat bbb
title           aaaaa
fdsaf
        title   bbbbb
        fdaf
[sniff:/tmp] > sed -n -r '
/^[^#]*title/{
x;s:\n::;x;H;
:read
n;
/^$|^#/{
x;s:.*::;x;s:^\n::;p;
b end;
}
/^[^#]*title/{
x;s:^\n::;p;s:.*::;x;H;
b read;
}
H;
b read;
}
p;
:end' bbb
title           aaaaa
fdsaf
[sniff:/tmp] > sed --version
GNU sed version 4.1.5
Copyright (C) 2003 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE,
to the extent permitted by law.
[sniff:/tmp] >
删除第二次匹配了
作者: Edengundam    时间: 2007-05-22 15:50
title   bbbbb
        fdaf
<<EOF>>
当然被干掉了....
还以为你说第一个满足那些条件的东西

[ 本帖最后由 Edengundam 于 2007-5-22 15:52 编辑 ]
作者: woodie    时间: 2007-05-22 15:51
如果不是GNUsed,改成下面这样试试看:
sed '/title/,${ /^$\|^#/,$b end; d;}; :end'
作者: chzht001    时间: 2007-05-22 15:59
原帖由 Edengundam 于 2007-5-22 15:50 发表
title   bbbbb
        fdaf
<<EOF>>
当然被干掉了....
还以为你说第一个满足那些条件的东西

注: 以下是简化版
我想是
[sniff:/tmp] > cat bbb
title           aaaaa
fdsaf
        title   bbbbb
        fdaf
<<EOF>>
处理后
[sniff:/tmp] > cat bbb
        title   bbbbb
        fdaf
<<EOF>>
[sniff:/tmp] >

[ 本帖最后由 chzht001 于 2007-5-22 16:12 编辑 ]
作者: chzht001    时间: 2007-05-22 16:05
原帖由 woodie 于 2007-5-22 15:46 发表
记忆中楼主的平台好像没有GNU工具,遗憾,那样的话楼上的代码就帮不上忙了。^_^


不过还是非常感谢woodie
作者: chzht001    时间: 2007-05-22 16:07
原帖由 Edengundam 于 2007-5-22 15:50 发表
title   bbbbb
        fdaf
<<EOF>>
当然被干掉了....
还以为你说第一个满足那些条件的东西


是第一个的,还没看懂你的代码,不太会改

[ 本帖最后由 chzht001 于 2007-5-22 16:10 编辑 ]
作者: chzht001    时间: 2007-05-22 16:32
原帖由 woodie 于 2007-5-22 15:51 发表
如果不是GNUsed,改成下面这样试试看:
sed '/title/,${ /^$\|^#/,$b end; d;}; :end'


对的,我又发现一个新情况,我没想到的
[sniff:/tmp] > cat bbb
title           aaaaa
fdsaf
#
        title   bbbbb
        fdaf

[sniff:/tmp] > sed '/title/,${ /^$\|^#/,$b end; d;}; :end' bbb
#
        title   bbbbb
        fdaf

[sniff:/tmp] >
[sniff:/tmp] > cat bbb
title           aaaaa
fdsaf
        title   bbbbb
        fdaf

[sniff:/tmp] > sed '/title/,${ /^$\|^#/,$b end; d;}; :end' bbb

[sniff:/tmp] >

当title后若干行(不满足匹配条件行若干行)又是title的情况

我想是下面这样
[sniff:/tmp] > cat bbb
title           aaaaa
fdsaf
        title   bbbbb
        fdaf

[sniff:/tmp] >
处理后
[sniff:/tmp] > cat bbb
        title   bbbbb
        fdaf

[sniff:/tmp] >

[ 本帖最后由 chzht001 于 2007-5-22 16:41 编辑 ]
作者: woodie    时间: 2007-05-22 18:25
18楼这种情况应该算作第4种情况:无合法的结尾,后面又开始新的title段。用GNU sed可以这样:
sed '/title/,${0,//d;0,/^$\|^#\|title/{//p;d};}'

[ 本帖最后由 woodie 于 2007-5-22 18:27 编辑 ]
作者: awk就是awp加ak    时间: 2007-05-22 20:11
try

  1. sed '
  2. x
  3. s,.,&,
  4. x
  5. t quit

  6. /title/{
  7.         h

  8.         :next
  9.         N

  10.         /\n[[:space:]]*$/b leftOneLine
  11.         /\n#/b leftOneLine
  12.         $b delete

  13.         b next

  14.         :leftOneLine
  15.         s,.*\n,,
  16.         b quit

  17.         :delete
  18.         d
  19. }

  20. :quit
  21. ' urfile
复制代码


相当难看 ^_^
作者: chzht001    时间: 2007-05-23 09:06
原帖由 woodie 于 2007-5-22 18:25 发表
18楼这种情况应该算作第4种情况:无合法的结尾,后面又开始新的title段。用GNU sed可以这样:
sed '/title/,${0,//d;0,/^$\|^#\|title/{//p;d};}'


太棒了,忍不住要赞一个

[ 本帖最后由 chzht001 于 2007-5-23 09:09 编辑 ]




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2