仅将全大写行转换为小写

仅将全大写行转换为小写

举个例子,假设我有:

One, Two.
OnE, Two.
ONE, TWO.

我只想将全部大写的行替换为小写,这样我就得到:

One, Two.
OnE, Two.
one, two.

我在尝试:

gsed '/[a-z]/!c\L&'

它正确匹配行,但将其替换为:L&

One, Two.
OnE, Two.
L&

如何将其转换为小写?

我在 L 之前尝试了 2 或 3 个反斜杠,但它只是将它们放入输出中。

如果有更好的选择,我将使用 awk 或 tr 或其他一些实用程序。

另外,如果版本很重要:

gsed --version
gsed (GNU sed) 4.9

答案1

使用任何 POSIX awk:

$ awk '!/[[:lower:]]/ { $0=tolower($0) } 1' file
One, Two.
OnE, Two.
one, two.

答案2

我认为你需要使用s///for&来工作,例如:

$ sed -e '/[a-z]/!s/.*/\L&/' < test.txt
One, Two.
OnE, Two.
one, two.

您可以使用 Perl 执行相同或类似的操作(这可能在 GNU sed 不可用的情况下可用):

% perl -pe 's/.*/\L$&/ if not /[[:lower:]]/' < test.txt
One, Two.
OnE, Two.
one, two.

或者:

% perl -pe '$_ = lc if not /[[:lower:]]/' < test.txt
One, Two.
OnE, Two.
one, two.

答案3

Perl的三元运算符:

$ perl -ne 'print /[a-z]/ ? $_ : lc' file
One, Two.
OnE, Two.
one, two.

说明

操作员 意义
perl 可执行文件
-n 解析当前文件内容,就像我们使用while (<>) ...
-e Perl的e表达
print 打印
/regex/ ? : 三元运算符,基于布尔结果的匹配regex
/[a-z]/ 如果有小写匹配...
$_ ...然后打印当前行的当前默认变量$_
lc l...否则打印ower ase中的当前行c(隐式使用$_

答案4

这是我的(简短而甜蜜的)Perl 解决方案:

perl -wpe '$_ = lc unless m/[a-z]/' file.txt

高级解释:这只是说:在打印 file 中的每一行之前file.txt,将该行转换为小写除非它包含所有小写字母。

您还可以替换m/[a-z]/tr/a-z//,使其看起来像这样:

perl -wpe '$_ = lc unless tr/a-z//' file.txt

它们之间的区别在于,m/[a-z]/旨在被评估为布尔值(即,它是否包含字符athru z),而tr/a-z//返回数字a至范围内的字符数z。 (如果它返回一个大于零的数字,则小写字母(即$_ = lc)将不是发生。)

哪一个更好?我还没有对它们进行基准测试,但差异可能很小,所以最好使用您更熟悉的那个。

但请记住:该m/[a-z]/方法使用[]方括号,而该tr/a-z//方法则没有,但以/连续两个 s 结尾。记住两者可能有点麻烦,所以我建议您使用更容易记住的一个。

相关内容