【问题标题】:Regular Expression - Sed正则表达式 - Sed
【发布时间】:2012-03-25 16:41:39
【问题描述】:

如何将四和五后面的逗号替换为 |但不是那些跟随一和二的人吗?

\"One,Two, Three\" Four, Five, Six

sed s'/,/|/'g

我希望得到一个可以应用于转义引号中的任何逗号的答案,而不仅仅是这个例子。

另一个例子是:

Mr ,Joe,Lish,,\"Acme, Inc.\",\"9599 Park Avenue, Suite 301\",Manhattan,NY,10022,\"\"\"6 A MAILING LIST MMBR GENERAL\"\"\"

【问题讨论】:

  • 一般来说,这种事情不是正则表达式的工作,因为你要求他们理解的语言是不规则的
  • 正确。正则表达式通常没有与 关联的 state,这是这里所需要的。解析器需要保留关于它是否在引号内的状态信息。

标签: regex sed


【解决方案1】:

一种使用sed的方式:

script.sed的内容:

## Substitute '\"' with '\n'.
s/\\\"/\n/g

## If there is an odd number of '\"' or the string doesn't end with '\"' I 
## will append some at the end. There is no danger, but it will be used to
## avoid an infinite loop.
## 1.- Save content to 'hold space'.
## 2.- Remove all characters except '\n'.
## 3.- Remove one of them because next command will add another one.
## 4.- Put content in 'pattern space' to begin working with it.
## So, if in original string there were 3 '\"', now there will be 6. ¡Fine!
h
s/[^\n]//g
s/\n//
H
g

## Label 'a'.
:a

## Save content to 'hold space'.
h

## Remove from first '\n' until end of line.
s/\(\n\).*$/\1/

## Substitute all commas with pipes.
s/,/|/g

## Delete first newline.
s/\n//

## Append content to print as final output to 'hold space'.
H

## Recover rest of line from 'hold space'.
g

## Remove content modified just before.
s/[^\n]*//

## Save content to 'hold space'.
h

## Get first content between '\n'.
s/\(\n[^\n]*\n\).*$/\1/
s/\n\{2,\}//

## Susbtitute '\n' with original '\"'.
s/\n/\\"/g

## Append content to print as final output to 'hold space'.
H

## Recover rest of line from 'hold space'.
g

## Remove content printed just before.
s/\n[^\n]*\n//

/^\n/ { 
    s/\n//g
    p   
    b   
}

ba

infile的内容:

\"One,Two, Three\" Four, Five, Six 
One \"Two\", Three, Four, Five
One \"Two, Three, Four, Five\"
One \"Two\" Three, Four \"Five, Six\"

像这样运行它:

sed -nf script.sed infile

结果如下:

\"One,Two, Three\" Four| Five| Six
One \"Two\"| Three| Four| Five
One \"Two, Three, Four, Five\"
One \"Two\" Three| Four \"Five, Six\"

【讨论】:

  • 响应为:未定义标签'a'
  • @adayzdone:抱歉,我无法重现您的问题。我的版本是 GNU sed 版本 4.2.1,你的是什么?
  • Mac 10.6.8自带的版本
【解决方案2】:

这可能对你有用:

 sed 's/^/\n/;:a;s/\n\("[^"]*"\|[^,]\)/\1\n/;ta;s/\n,/|\n/;ta;s/.$//' file

解释:

  • 在模式空间前添加一个换行符。 s/^/\n/
  • 制作标签:a
  • 在引号之间的字符串或非逗号字符上移动换行符。 s/\n\("[^"]*"\|[^,]\)/\1\n/
  • 如果替换成功循环标记。 ta
  • \n, 替换|\ns/\n,/|\n/
  • 如果替换成功循环标记。 ta
  • 如果没有发生替换,则全部删除换行符。 s/.$//

编辑:

实际上可以使用任何唯一字符或字符组合来代替\n

echo 'Mr ,Joe,Lish,,\"Acme, Inc.\",\"9599 Park Avenue, Suite 301\",Manhattan,NY,10022,\"\"\"6 A MAILING LIST MMBR GENERAL\"\"\"' | 
sed 's/^/@@@/;:a;s/@@@\("[^"]*"\|[^,]\)/\1@@@/;ta;s/@@@,/|@@@/;ta;s/@@@$//'
Mr |Joe|Lish||\"Acme, Inc.\"|\"9599 Park Avenue, Suite 301\"|Manhattan|NY|10022|\"\"\"6 A MAILING LIST MMBR GENERAL\"\"\"

【讨论】:

  • 看起来您的 sed 版本不允许 \n 形式的换行符。如果使用 bash 作为 shell,请尝试将所有 \n 替换为 '"$'\n'"',或者通过键入 CTRL-v return 插入真正的换行符。另见here
【解决方案3】:

正则表达式有lookahead 和lookbehind 运算符。比如Javascript调用

bodyText = bodyText.replace(/Aa(?=A)/g, 'AaB');

如果文本“Aa”后面跟着另一个“A”,则将文本“Aa”替换为“AaB”,留下“AaBA”。它不会匹配“AaB”,因为“Aa”后面没有另一个“A”。这是一个前瞻调用。

我相信lookbehind的语法是?

因此,如果您正在使用的软件包支持这些运算符,那么您可以使用它们来匹配前面有“Four”或“Five”的“,”,并且只替换“,”。

【讨论】:

  • @dmckee 如果你alias sed="perl -p",那么它会正常工作。 :)
  • @tchrist:你是​​个病态的人。但是很聪明。我的意思是,以一种的方式。
【解决方案4】:

我想出了这个:

 echo '\"One,Two, Three\" Four, Five, Six' | sed 's/\(\("[^"]*"\)\?[^",]\+\),/\1 |/g'

假设一行就像

  [ ["someting"] word, ]* ["someting"] word

【讨论】:

  • 这对我不起作用。如果有任何改变,我正在使用终端的 Mac 上。
猜你喜欢
  • 2018-11-11
  • 1970-01-01
  • 1970-01-01
  • 2017-07-28
  • 1970-01-01
  • 1970-01-01
  • 2017-12-18
  • 2010-09-19
  • 2018-08-22
相关资源
最近更新 更多