分页: 1 / 1

一个sed题

发表于 : 2011-11-29 7:04
fnan
在chinaunix.net看到的sed问题,谁有兴趣玩玩,还没见到有好的方案:
字符串操作有一个需求,示例
a b c d ea b c d ea b c d e
只使用sed操作,要求把空格替换成\t ,sed遇到第一个ea的时候自动跳出替换当遇到第二个ea的时候接着执行替换,一行有N个ea 有n行
该如何操作?

Re: 一个sed题

发表于 : 2011-11-29 11:12
vinoca
用sed不好实现,这种任务用awk处理比较合适。

Re: 一个sed题

发表于 : 2011-11-29 11:16
tangboyun
提供几个恶心的测试用例:
a b c d ea b c d ea b c d e ea
ea ea ea
ea ea ea
ea b ea b ea
b ea b ea b ea

应该输出:

a空b空c空d空ea b c d ea空b空c空d空e空ea
ea ea空ea
ea ea空ea
ea b ea空b空ea
b空ea b ea空b空ea

我sed水平不行,用haskell写了个。假设项里不会再嵌套空格,且遇到奇数ea执行,偶数不执行。该替换的空格用汉字’空‘显示。主要是split这块写了很多无法简化。
[haskell]
{-# LANGUAGE BangPatterns #-}
module Main where
import Data.List
import System.Environment

splitEveryEA :: String -> [String]
splitEveryEA str | "ea " `isPrefixOf` str = "" : go [] [] str
| otherwise = go [] [] str
where
go :: String -> [String] -> String -> [String]
go !acc !lss [] = lss ++ [acc]
go !acc !lss " ea" = lss ++ [acc++" "] ++ ["ea"]
go !acc !lss (x:xs) | " ea " `isPrefixOf` xs
= go [] (lss ++ [acc ++ [x] ++ " "]) (tail xs)
| otherwise
= go (acc ++ [x]) lss xs

main :: IO ()
main = do
fmap head getArgs >>= readFile >>=
\content ->
sequence_ [putStrLn $ concat $
zipWith ($) f (splitEveryEA l) | l <- lines content]
where
f = cycle [spaceToTab,id]
spaceToTab [] = []
spaceToTab (x:xs) | x == ' ' = '空' : spaceToTab xs
| otherwise = x:spaceToTab xs
[/haskell]

Re: 一个sed题

发表于 : 2011-11-30 2:03
fnan
#用X H做个华丽演习:
第一步 sed -r ':a;N;$!ba; s/\bea\b|$/X/g;' f.txt
a b c d X b c d X b c d e X
X X X
X X X
X b X b X
b X b X b X X
第二步 sed -r ':a;N;$!ba; s/\bea\b|$/X/g; s/X[^X]*X| /&H/g;' f.txt
a Hb Hc Hd HX b c d XH Hb Hc Hd He HX
XH HX XH
X XH HX
XH Hb HX b XH
b HX b XH Hb HX XH
第三步 sed -r ':a;N;$!ba; s/\bea\b|$/X/g; s/X[^X]*X| /&H/g; s/ H/\t/g;' f.txt
a b c d X b c d XH b c d e X
XH X XH
X XH X
XH b X b XH
b X b XH b X XH
完成 sed -r ':a;N;$!ba; s/\bea\b|$/X/g; s/X[^X]*X| /&H/g; s/ H/空/g; s/X|XH/ea/g' f.txt
a空b空c空d空ea b c d ea空b空c空d空e空ea
ea空ea ea
ea ea空ea
ea空b空ea b ea
b空ea b ea空b空ea ea

Re: 一个sed题

发表于 : 2011-11-30 2:18
fnan
应该输出:

a空b空c空d空ea b c d ea空b空c空d空e空ea
ea ea空ea
ea ea空ea
ea b ea空b空ea
b空ea b ea空b空ea
第一和第二行如果一连三个ea,必有 空 的,因为跨行匹配。

Re: 一个sed题

发表于 : 2011-11-30 5:14
fnan
#实用写法:
cat f.txt
a b c d ea b c d ea b c d e ea
ea ea ea
ea ea ea
ea b ea b ea
b ea b ea b ea
sed -r ':a;N;$!ba; s/\bea\b|$/&\x1a/g; s/\x1a[^\x1a]*\x1a| /&\x1b/g; s/ \x1b/空/g; s/\x1a|\x1b//g' f.txt
a空b空c空d空ea b c d ea空b空c空d空e空ea
ea空ea ea
ea ea空ea
ea空b空ea b ea
b空ea b ea空b空ea
cat file.txt
a b c d ea b c d ea b c d e
a b c d ea b c d ea b c d eabc ea jh
a b c
a b c d ea b c d ea b c d e
a b c d ea b c d b c d e
sed -r ':a;N;$!ba; s/\bea\b|$/&\x1a/g; s/\x1a[^\x1a]*\x1a| /&\x1b/g; s/ \x1b/空/g; s/\x1a|\x1b//g' file.txt
a空b空c空d空ea b c d ea空b空c空d空e
a空b空c空d空ea b c d ea空b空c空d空eabc空ea jh
a b c
a b c d ea空b空c空d空ea b c d e
a b c d ea空b空c空d空b空c空d空e

Re: 一个sed题

发表于 : 2011-11-30 9:57
eexpress
http://eexpress.oldblog.ubuntu.org.cn/2 ... l-version/

看懂这个。你sed就毕业了。

Re: 一个sed题

发表于 : 2011-11-30 11:16
tangboyun
额,我要补语文了,我以为楼主的是要每行分开考虑。sed这玩意儿我开man看半天还是累,不是经常用的话用法容易忘呀。 :em20

Re: 一个sed题

发表于 : 2011-11-30 18:04
MaskRay
[haskell]
f b (' ':xs) = (if b then '空' else ' '):f b xs
f b ('e':'a':xs) = 'e':'a':f (not b) xs
f b (x:xs) = x:f b xs
f b "" = ""
main = interact $ unlines . map (f True) . lines
[/haskell]

Re: 一个sed题

发表于 : 2011-11-30 18:15
fnan
题目是照抄的,通常写得不会很明确。

Re: 一个sed题

发表于 : 2011-11-30 23:56
tangboyun
MaskRay 写了:[haskell]
f b (' ':xs) = (if b then '空' else ' '):f b xs
f b ('e':'a':xs) = 'e':'a':f (not b) xs
f b (x:xs) = x:f b xs
f b "" = ""
main = interact $ unlines . map (f True) . lines
[/haskell]
这个interact用的很棒也,不过split的处理无法区分包含字母ea的项,恶心在split上,haskell里调正则不如脚本方便。