0

假设我有类似的东西:

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

sed 的典型用法是将“疯狂大小写”字符串转换为混合大小写(第一个字母大写,其余字母小写)

但是,这将始终影响整个字符串。例如,如果我想解析各种风格的“疯狂”mp3 文件名($tracknr - $artist - $title 与 $artist - $tracknr - $title),事情会变得更加复杂,因为有时标题是外语的像法语和混合大小写在法语或意大利语中看起来很糟糕。这就是为什么我只想继续直到达到某个分隔符,例如空格-破折号-空格。

因此,我想使用组合的 's/.../...' 表达式来一步一步地做事。但是,如果有一种方法可以从 PREVIOUS 表达式中“存储”子表达式,让我能够将保留的子匹配用作下一个 sed 替换表达式的源表达式,那就太好了。

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

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

有什么东西可以执行这种事情吗?

4

4 回答 4

2

问题

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

您的问题使您的生活变得比必要的更艰难

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

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

简单的 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'

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

等等等等等等

于 2012-06-12T21:38:54.633 回答
2

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

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

您可以使用这个替代方案(它仍然是 GNU 主义,请参阅\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
于 2012-06-12T21:43:10.803 回答
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)
于 2012-06-12T21:55:35.967 回答
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
于 2012-06-12T22:06:39.597 回答