sed's / ... / ...':是否可以存储子表达式供以后使用?

时间:2012-06-12 21:18:19

标签: sed backreference

假设我有类似的东西:

echo "bLah BLaH blAH" | sed -r 's/([a-zA-Z ]+)/\L&; s/[a-z]/\u&/g'

相当典型的用于sed将“疯狂案例”字符串变为混合大小写(首字母大写,其余字母小写)

但是,这将始终影响WHOLE字符串。例如,如果我想解析各种风格的“疯狂”mp3文件名($ tracknr - $ artist - $ title vs. $ artist - $ tracknr - $ title),事情变得更加复杂,因为有时标题是外语像法国和混合案例只是看起来像法国或意大利的BUTT-UGLY。这就是为什么我只想继续到达某个分隔符,例如e。 G。空间划线空间。

因此,我想使用组合的'/ ... / ...'表达式来逐步完成。 但是,有一种方法可以从PREVIOUS表达式“存储”子表达式,以便能够将保留的子匹配作为源表达式用于下一个sed替换表达式。

如果您认为无论如何都能使用OOTB,那就错了。您只是不能在分号后面的第二个表达式中使用'\ 1'语法来引用前一个表达式的子表达式(当然,一旦您在 second 表达式中定义了一个子表达式,它就会起作用,但这种可能性现在不考虑)。就我而言,解析器只是未知,你会得到错误

sed: -e expression #1, char (xx): invalid reference \1 on `s' command's RHS

是否有任何实现可以执行此类事情?

4 个答案:

答案 0 :(得分:2)

问题

您希望将每个单词的第一个字母大写。

你的问题使你的生活比必要的更难

您可以将文本存储在保留空间中,也可以使用顺序表达式和嵌套表达式对匹配的模式执行多个操作。您甚至可以使用保留空间来拉动一些恶作剧来重新处理线。但是,过去一定程度的复杂性,真正的问题不是“语言X能做到这一点吗?”而是“为此优化了哪种语言?”

如果你想通过规范的PCRE引擎进行繁重的文本处理并通过复杂的逻辑跟踪子表达式,Perl是一个更好的选择。任何图灵完备的语言都可以,但Perl的一个反面词是“病态折衷的垃圾列表”,这是有原因的。

Easy GNU sed解决方案

您不需要所要求的所有复杂性。一些基本的GNU sed扩展可以做你想要的。

echo "bLah BLaH blAH" |
sed -r 's/(\b[a-zA-Z ]+\b)/\L&/g; s/\b[a-zA-Z ]/\u&/g'

这会产生大写每个单词的第一个字符的所需输出:

  Blah Blah Blah

答案 1 :(得分:2)

假设@CodeGnome做对了,你想要的是

  

您希望将每个单词的第一个字母大写。

您可以使用此替代方案(仍然是GNU-ism,请参阅\L \U):

sed 's;\(.\)\([^ ]*\) \?;\U\1\L\2 ;g'

你的例子:

$ echo "bLah BLaH blAH" | sed 's;\(.\)\([^ ]*\) \?;\U\1\L\2 ;g'
Blah Blah Blah

如果除了sed之外你还可以使用其他解决方案,你可以使用awk并使用GNU-isms(感谢IRC上的dualbus)

awk '{for(i=1;i<=NF;i++){$i=toupper(substr($i,1,1))tolower(substr($i,2))}}1'

示例:

$ echo "bLah BLaH blAH" | awk '{for(i=1;i<=NF;i++){$i=toupper(substr($i,1,1))tolower(substr($i,2))}}1'
Blah Blah Blah

答案 2 :(得分:1)

Perl单线方法;)

echo "bLah BLaH blAH" |
    perl -ne '@_ = map { ucfirst } split; print join " ", @_, $/'
BLah BLaH BlAH

这适用于任何 Unices 我猜=)

我会分解它:

perl         # ?! dunno =)
-n           # assume "while (<>) { ... }" loop around program
-e           # one line of program (several -e's allowed, omit programfile)
@_           # default array name
=            # what you expect
map          # take a list as argument, and perform modification. Return a list
{ ucfirst }  # modification on the list
split        # without argument, takes the current line (we use -n switch)
;            # end of the first instruction
print        # what you expect
join " ", @_ # join a space on the list
$/           # by default, a newline (see perldoc perlvar)

答案 3 :(得分:1)

或者在awk中,没有正则表达式的开销:

[ghoti@pc ~]$ echo "bLah BLaH blAH" | awk 'BEGIN{RS=" ";ORS=RS} {print toupper(substr($0,1,1)) tolower(substr($0,2))}'
Blah Blah Blah