如何使用 tr 将任何文本更改为正确大小写和句子大小写?

如何使用 tr 将任何文本更改为正确大小写和句子大小写?

根据https://caseconverter.com/

“大写”将所有字母转换成这样的大写字母。

“小写”将所有字母转换为小写字母,如下所示。

“正确的大小写”将文本转换为每个单词的第一个字母都大写,如下所示

《句案》。这会将每个句子的第一个字母大写,并将文本的其余部分转换为小写。因此,每个句号后的第一个字母会自动转换为大写字母。

前两个可以通过命令轻松完成tr

user@linux:~$ tr [:lower:] [:upper:] <<< eXaMPLe
EXAMPLE
user@linux:~$ 

user@linux:~$ tr [:upper:] [:lower:] <<< eXaMPLe
example
user@linux:~$ 

或者

user@linux:~$ tr [a-z] [A-Z] <<< eXaMPLe
EXAMPLE
user@linux:~$ 

user@linux:~$ tr [A-Z] [a-z] <<< eXaMPLe
example
user@linux:~$ 

最后两个“正确案例”和“句子案例”怎么样?

是否可以?

如果是,请告诉我。

如果不是,还有什么替代方案?

答案1

请注意,除非您的 shellfish不支持[...]通配符,否则您应该引用这些[:lower:], [A-Z],否则 shell 可能会将它们扩展到当前目录中的匹配文件列表(如果不匹配则报告错误):

tr '[:lower:]' '[:upper:]'

其他注意事项:

  • GNU 实现tr仅支持单字节字符,因此在 UTF-8 语言环境中,它只会大写英文字母而不带变音符号。
  • tr '[A-Z]' '[a-z]'很好,但你也可以简单地这样做tr A-Z a-z(在 POSIX 兼容的实现中)。但是,它只能保证仅ABCDEFGHIJKLMNOPQRSTUVWXYZ在 C/POSIX 语言环境中匹配。

要将每个单词的第一个字母大写,使用 的 GNU 实现sed,您可以执行以下操作:

sed -E "s/[[:alnum:]_'-]+/\u&/g"

我们包括', -,但_不包括其他标点符号,以便foo-bar2baz,foo变成Foo-bar2baz,Foo

这适用于多字节字符,但通常不适用于组合字符,因为大多数语言环境不会将它们视为alnum

$ echo $'ste\u0301phane' | sed -E "s/[[:alnum:]_']+/\u&/g"
StéPhane

要考虑这些,您可以切换到perl,其中这些可以与 匹配\pM

$ echo $'ste\u0301phane chazelas' | perl -Mopen=locale -pe 's/[\w\pM'\''-]+/\u$&/g'
Stéphane Chazelas

另请注意,这会将first(其第一个字符是连字 字符)转换为FIrst。使用ucfirst()而不是uc()/\u可以避免这种情况:

$ echo 'first second' | perl -Mopen=locale -pe 's/[\w\pM'\''-]+/ucfirst$&/ge'
First Second

对于句子大写,这是相当棘手的,你必须将文本开头或句子分隔符(如.,,?... )或句子介绍符(¿¡)之后的第一个字母大写,之间允许任意数量的空格,但是还有诸如(, [, ", , , «... 之类的东西)。根据您想要支持的语言,您可能需要考虑更多。

你可以用类似的东西来做到这perl一点:

perl -0777 -C -pe 's/(^|[.!?…⁇⁈⁉¿¡])[\s([{"`‶‷«]*\K\p{Ll}/ucfirst$&/ge'

这里假设使用 UTF-8 语言环境和输入,并且仅涵盖其中的一些情况。

无论如何,这不是tr单靠tr音译就能完成的事情每一个字符,不能叫只音译一些。

答案2

不,单独行动是不可能的trtr不理解完成这项工作所需的单词或句子。

作为替代方案,您可以尝试 Perl 及其强大的模式引擎:

$ perl -pe 's/\b[\p{L}\p{Pd}]+/ucfirst lc $&/ge' <<< 'A HEART-SHAPED BOX'
A Heart-shaped Box
$ perl -pe 's/\p{L}.*?[.?!]/ucfirst lc $&/ge' <<< 'for sale. baby shoes. never worn.'
For sale. Baby shoes. Never worn.

然而,上面的解决方案是一个快速而肮脏的解决方案,并没有涵盖所有可能的情况,并且需要进行调整(非拉丁字母和非 ASCII 拉丁字母、依赖于语言环境的情况、文章不大写) 、句子中的专有名词大写等)。话又说回来,两者都做不到tr

答案3

tr只将单个字符更改为其他单个字符(或删除它们),并且它不了解任何字符的上下文。因此,它无法区分单词开头、中间或结尾的字符。它甚至不知道什么是“词”。

将文本更改为标题大小写(你所说的“适当的情况”)或句子情况是不可能使用的tr

您需要一个工具来为单个角色提供一些背景信息。

这是一个简单的 GNUsed程序,它通过匹配单独的单词并更改其第一个字符来将文本转换为标题大小写:

$ sed 's/\<\([[:lower:]]\)\([[:alnum:]]*\)/\u\1\2/g' file
There Is No Danger On The Roof. There Is No Cow On The Ice.

\<非单词字符和单词字符之间的转换点(即单词开头)的匹配。正则表达式的其余部分匹配小写字母,后跟任意数量的字母数字字符。如果匹配,它将小写字母更改为大写字母并附加单词的其余部分。第一个字母的大写使用 GNUsed扩展(这不适用于大多数其他sed实现)。

对于文本的句子外壳,还有另一个简单的 GNUsed变体:

$ sed 's/\<\([[:lower:]]\)\([^[:punct:]]*\)/\u\1\2/g' file
There is no danger on the roof. There is no cow on the ice.

这或多或少又是相同的事情,但是我们不是匹配字母数字字符的单词,而是匹配不是标点符号的字符串。

请注意,这仅适用于您在问题中显示的类型的非常简单的文本。sed例如,第二个, 无法正确处理问题what's that?,因为'它是与 匹配的标点符号[[:punct:]]

答案4

zsh前三个具有L, U,参数扩展标志,第一个也具有csh-style /修饰符或 ksh-style / ,并且可以使用捕获组使用 ksh-style 执行第四个。C:l:utypeset -u-l${param//pattern/replacement}

text='The RIVER dee in Aberdeen can be cold,
 so i shiver when i swim. Scotland is STILL beaUtIful though.
 eveN when it RAINS? "YES! of course", is the obvious answer.'
$ print -r -- ${(L)text}
the river dee in aberdeen can be cold,
 so i shiver when i swim. scotland is still beautiful though.
 even when it rains? "yes! of course", is the obvious answer.
$ print -r -- ${(U)text}
THE RIVER DEE IN ABERDEEN CAN BE COLD,
 SO I SHIVER WHEN I SWIM. SCOTLAND IS STILL BEAUTIFUL THOUGH.
 EVEN WHEN IT RAINS? "YES! OF COURSE", IS THE OBVIOUS ANSWER.
$ print -r -- ${(C)text}
The River Dee In Aberdeen Can Be Cold,
 So I Shiver When I Swim. Scotland Is Still Beautiful Though.
 Even When It Rains? "Yes! Of Course", Is The Obvious Answer.
$ print -r -- $text:l
the river dee in aberdeen can be cold,
 so i shiver when i swim. scotland is still beautiful though.
 even when it rains? "yes! of course", is the obvious answer.
$ print -r -- $text:u
THE RIVER DEE IN ABERDEEN CAN BE COLD,
 SO I SHIVER WHEN I SWIM. SCOTLAND IS STILL BEAUTIFUL THOUGH.
 EVEN WHEN IT RAINS? "YES! OF COURSE", IS THE OBVIOUS ANSWER.
$ typeset -l text
$ print -r -- $text
the river dee in aberdeen can be cold,
 so i shiver when i swim. scotland is still beautiful though.
 even when it rains? "yes! of course", is the obvious answer.
$ typeset -u text
$ print -r -- $text
THE RIVER DEE IN ABERDEEN CAN BE COLD,
 SO I SHIVER WHEN I SWIM. SCOTLAND IS STILL BEAUTIFUL THOUGH.
 EVEN WHEN IT RAINS? "YES! OF COURSE", IS THE OBVIOUS ANSWER.
$ set -o extendedglob
$ typeset +u text
$ print -r -- ${${text:l}//(#b)(((#s)|[.!?…⁇⁈⁉¿¡])[[:space:][\{\"\`‶‷«]#)([[:lower:]])/$match[1]${match[3]:u}}
The river dee in aberdeen can be cold,
 so i shiver when i swim. Scotland is still beautiful though.
 Even when it rains? "Yes! Of course", is the obvious answer.

与我的其他答案中的警告相同。

相关内容