我有这个测试文件。使用sed替换文本只是在引号中
[[email protected] ~]# cat f.txt "a aa" MM "bbb b" MM MM MM"b b " [[email protected] ~]#
我想用引号替换引号中的所有空格字符,只是在引号中。所有不包括引号的字符都不应该被触及。也就是说,我要的是类似于:
"a_aa" MM "bbb__b" MM MM MM"b_b_"
可以这样使用的sed实施?
谢谢,
我有这个测试文件。使用sed替换文本只是在引号中
[[email protected] ~]# cat f.txt "a aa" MM "bbb b" MM MM MM"b b " [[email protected] ~]#
我想用引号替换引号中的所有空格字符,只是在引号中。所有不包括引号的字符都不应该被触及。也就是说,我要的是类似于:
"a_aa" MM "bbb__b" MM MM MM"b_b_"
可以这样使用的sed实施?
谢谢,
这是一个完全不重要的问题。
这适用于下划线代替,引号里的第一空间:
$ sed 's/\("[^ "]*\) \([^"]*"\)/\1_\2/g' f.txt
"a_aa" MM "bbb_ b"
MM MM
MM"b_b "
$
在这个例子中,在里面有任何的报价不超过两个空间,人们很容易简单地重复命令,但它给出了一个不正确的结果:
$ sed -e 's/\("[^ "]*\) \([^"]*"\)/\1_\2/g' \
> -e 's/\("[^ "]*\) \([^"]*"\)/\1_\2/g' f.txt
"a_aa"_ MM "bbb_ b"
MM MM
MM"b_b_"
$
如果你的的sed
版本支持“扩展正则表达式”,那么这个工程的样本数据:
$ sed -E \
> -e 's/^(([^"]*("[^ "]*")?)*)("[^ "]*) ([^"]*")/\1\4_\5/' \
> -e 's/^(([^"]*("[^ "]*")?)*)("[^ "]*) ([^"]*")/\1\4_\5/' \
> -e 's/^(([^"]*("[^ "]*")?)*)("[^ "]*) ([^"]*")/\1\4_\5/' \
> f.txt
"a_aa" MM "bbb__b"
MM MM
MM"b_b_"
$
对于双引号内的每个空格,你必须重复那个可怕的正则表达式 - 因此对于第一行数据来说是三次。
正则表达式可以如解释:
因为起步锚的,这必须每空重复一次......但sed
具有循环结构,所以我们可以做到这一点:
$ sed -E -e ':redo
> s/^(([^"]*("[^ "]*")?)*)("[^ "]*) ([^"]*")/\1\4_\5/
> t redo' f.txt
"a_aa" MM "bbb__b"
MM MM
MM"b_b_"
$
的:redo
定义了一个标签; s///
命令与以前一样;如果自从上一次读取一行或跳转到标签以来进行了任何替换,则t redo
命令将跳转到标签。
鉴于该意见的讨论中,有几个值得一提的几点:
的-E
选项适用于sed
在MacOS X(10.7.2测试)。GNU版本sed
的相应选项是-r
(或--regex-extended
)。 -E
选项与grep -E
(它也使用扩展正则表达式)一致。 “经典Unix系统”不支持sed
(Solaris 10,AIX 6,HP-UX 11)的ERE。
可以代替我用了?
(这是强制使用的ERE,而不是BRE的唯一字符)与*
,然后用括号(需要反斜杠在一个BRE他们面前处理使他们成为捕获括号),使脚本:
sed -e ':redo
s/^\(\([^"]*\("[^ "]*"\)*\)*\)\("[^ "]*\) \([^"]*"\)/\1\4_\5/g
t redo' f.txt
这将产生相同的输入相同的输出 - 我试着输入一些稍微复杂的图案:
"a aa" MM "bbb b"
MM MM
MM"b b "
"c c""d d""e e" X " f "" g "
"C C" "D D" "E E" x " F " " G "
氏s给出的输出:
"a_aa" MM "bbb__b"
MM MM
MM"b_b_"
"c_c""d_d""e__e" X "_f_""_g_"
"C_C" "D_D" "E__E" x "_F_" "_G_"
即使BRE符号,sed
支持\{0,1\}
表示法指定0或1次出现先前RE术语,所以?
版本可以使用被转换为BRE:
sed -e ':redo
s/^\(\([^"]*\("[^ "]*"\)\{0,1\}\)*\)\("[^ "]*\) \([^"]*"\)/\1\4_\5/g
t redo' f.txt
这产生与其他选择相同的输出。
谢谢你。优秀的解决方但是扩展的正则表达式开关在我的系统上是*** - r ***。 –
@JonathanLeffler优秀的正则表达式使用,特别是'(“[^”] *“)?'碰撞替代,但为什么'?'而不是'*'? – potong
我认为你可以使用'?'或'* ''成功了('*'处理样本数据)。我使用'?'是因为它可能有助于限制正则表达式的回溯数量,这非常复杂(这不是我想要的正则表达式必须急于破译!)。 –
一个莫名其妙不寻常的答案XSLT 2.0:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="text"></xsl:output>
<xsl:template name="init">
<xsl:for-each select="tokenize(unparsed-text('f.txt'),' ')">
<xsl:for-each select="tokenize(.,'"')">
<xsl:value-of select="if (position() mod 2 = 0)
then concat('"',translate(.,' ','_'),'"') else ."></xsl:value-of>
</xsl:for-each>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
为了测试是否,只得到sourceforge上saxon.jar并使用以下命令行:
java -jar saxon9.jar -it:init regexp.xsl
XSLT文件包含对f.txt的引用,则文本文件必须与xslt文件位于同一目录中。通过给样式表一个参数可以很容易地改变它。
它在一次通过。
如果引用的文本全部在不同的行上,这将非常简单。所以一种方法是分割文本,这样你就可以做到,做简单的转换,然后重建线条。
拆分文本是容易的,但我们需要的是为
为了做到这一点,我们可以用符号表示它属于哪个类的每一行结束。我会用1和2,直接对应上面的。在SED,我们有:
sed -e 's/$/1/' -e 's/"[^"]*"/2\n&2\n/g'
这将产生:
2
"a aa"2
MM 2
"bbb b"2
1
MM MM1
MM2
"b b "2
1
这很容易进行改造,只需使用
sed -e '/".*"/ s/ /_/g'
给
2
"a_aa"2
MM 2
"bbb__b"2
1
MM MM1
MM2
"b_b_"2
1
最后,我们需要把它放回去。这实际上是在SED很可怕,但使用的保留空间是可行的:(这将是更清晰了很多,例如,AWK)
sed -e '/1$/ {s/1$//;H;s/.*//;x;s/\n//g}' -e '/2$/ {s/2$//;H;d}'
管的三个步骤在一起,你就大功告成了。
这可能会为你工作:
sed 's/^/\n/;:a;s/\(\n[^"]*"[^ "]*\) \([^"]*"\)\n*/\1_\2\n/;ta;s/\n//;ta;s/\n//' file
说明:
前面加上一个\n
到线的起点,这将被用来沿着换人磕碰。在"
之内替换一个与
_
,然后在那里为\n
准备好下一轮替换。取代所有后,删除
\n
并重复。当发生所有替换时,请删除\n
分隔符。
或该:
sed -r ':a;s/"/\n/;s/"/\n/;:b;s/(\n[^\n ]*) ([^\n]*\n)/\1_\2/g;tb;s/\n/%%%/g;ta;s/%%%/"/g' file
说明:
“与\n
小号的替换第一组""
。用_
替换换行符之间的第一个空格,重复。将\n
替换为一个唯一的分隔符(%%%
),从头开始重复。最后用"
代替所有%%%
。
的第三种方式:
sed 's/"[^"]*"/\n&\n/g;$!s/$/@@@/' file |
sed '/"/y/ /_/;1{h;d};H;${x;s/\n//g;s/@@@/\n/g;p};d'
说明:
环绕所有引用的表达式("..."
)与换行符(\n
的)。在除最后一行之外的所有行上插入行尾分隔符@@@
。将结果传递给第二个sed
命令。将的全部内容翻译为
_
,其中的内容为"
。将每条线存放在容纳空间(HS)中。在文件中,交换到HS的结束,并删除所有\n
的,并与\n
代替结束行分隔符的
最后:
sed 's/\("[^"]*"\)/$(tr '"' ' '_'"'<<<'"'"'\1'"'"')/g;s/^/echo /' file | sh
或GNU sed的:
sed 's/\("[^"]*"\)/$(tr '"' ' '_'"'<<<'"'"'\1'"'"')/g;s/^/echo /e' file
留给读者解决。
顺便说一句:好问题 - 特别是有很好的示例输入和所需的输出。 –