【问题标题】:Perl, using tr function to convert uppercase to lowercase and vice-versa at the same time?Perl,使用tr函数同时将大写转换为小写,反之亦然?
【发布时间】:2011-04-09 21:31:01
【问题描述】:

我有一个字符串

$string= 'AbCdEf';

我想使用 tr 函数同时将所有大写字母转换为小写字母,并将所有小写字母转换为大写字母....。我基本上只是想把它倒过来变成。

aBcDeF

我想出了这条线,但我不知道如何修改它来做我想要的。有什么帮助吗?

$string=~ tr/A-Z/a-z/;

谢谢!

【问题讨论】:

  • 我假设您希望保留那些没有小写对应的大写字母,反之亦然 - 对吧?这就是我在解决方案中所做的。一个例子是人们对 number 使用的缩写:“Nº”。缩写的第一个字母是大写的,在“n”中有一个小写形式,但它的第二个字母是一个小写字母,没有对应的大写版本。因此,如果您交换大小写,那将只是“nº”,因为无法在 0xBA(即 º 是什么)之类的东西上交换大小写,即使它被认为是小写。

标签: perl case-conversion


【解决方案1】:

应 Tom 的要求,Unicode-clean(或 locales-clean)版本:

s/([[:upper:]])|([[:lower:]])/defined $1 ? lc $1 : uc $2/eg

【讨论】:

  • @tchrist true,但也更有可能有人无需花一个小时咨询 unicode 属性参考就可以阅读它,而 AFAICT 这只是一个性能问题,而不是正确性问题 :)
  • 嗯...这可能是一个正确性问题。我不知道。问题没有很好地说明。但是我的版本确实会改变标题化的东西。如果您不喜欢\p{CWU}\p{CWL},我们非常欢迎您使用\p{Changes_When_Uppercased}\p{Changes_When_Lowercased}。如果您真的需要查看这意味着什么,我怀疑英语词典在这里可能比 Unicode 标准更有用。 :)
  • 另外,我永远不会使用像 [[:upper:]] 这样的遗留 POSIX 东西。语言环境令人讨厌。您真的想改用 Unicode。看着 perlrecharclass 手册页中涉及 POSIX 语言环境的所有内容,我感到非常紧张。我不喜欢解析\p{PosixAlpha} vs ASCII alpha vs \p{XPosixAlpha}。如果您使用的是语言环境,那么您有 8 位旧数据,由于某种原因忘记正确解码。我没有想到什么?
【解决方案2】:

$string =~ tr/A-Za-z/a-zA-Z/;

【讨论】:

  • 是的,现代解决方案是什么,不是卡在 7 位ᴀsᴄɪɪ 中的解决方案? :)
  • 如果您正在使用简单的 7 位 ASCII 码,那么它没有任何问题。
  • 当有人说“全部大写”时,他们要求的是\p{Upper},而不是[A-Z]。与“所有小写字母”类似,他们要求\p{Lower} 而不是[a-z]。 a-z 和 A-Z 都有一种代码气味:“它们总是错的——有时。”当多一点小心可以保证我永远不会出错时,我讨厌被保证有时会出错。这就像在非常非常小的比赛条件和根本没有比赛条件之间有天壤之别。细心的程序员只知道这两种情况中的一种是正确的,所以总是避免另一种情况。
【解决方案3】:

您可以通过以下方式完成完整的 Unicode 解决方案:

s/ (\p{CWU}) | (\p{CWL}) / 定义 $1 ? uc $1 : lc $2/gex;

或者这样

s/ (\p{CWL}) | (\p{CWU}) / 定义 $1 ? lc $1 : uc $2/gex;

取决于你想对在两个方向上改变大小写的东西做什么,比如Dz,它的大写是DZ,它的小写是dz。

如果您在此输入中运行这两个替换中的第二个:

@ 0040 商业在 © 00A9 版权所有 Å 212B 埃格斯特罗姆标志 ⒜ 249C 带括号的拉丁文小写字母 A Ⓐ 24B6 带圆圈的拉丁文大写字母 A ⓐ 24D0 带圆圈的拉丁文小写字母 A 一个 FF21 全宽拉丁文大写字母 A 一个 FF41 全宽拉丁小写字母 A Ⓒ 24B8 带圆圈的拉丁文大写字母 C ⓒ 24D2 带圆圈的拉丁文小写字母 C DZ 01F1 拉丁文大写字母 DZ Dz 01F2 拉丁文大写字母 D 和小写字母 Z dz 01F3 拉丁文小写字母 DZ ⅲ 2172 小罗马数字三 S 0053 拉丁文大写字母 S s 0073 拉丁文小写字母 S ſ 017F 拉丁文小写字母 LONG S ⒮ 24AE 带括号的拉丁文小写字母 S Ⓢ 24C8 带圆圈的拉丁文大写字母 S ⓢ 24E2 带圆圈的拉丁文小写字母 S Ꞅ A784 拉丁文大写字母 INSULAR S ꞅ A785 拉丁小写字母 INSULAR S ß 00DF 拉丁文小写字母 SHARP S ẞ 1E9E 拉丁文大写字母 SHARP S Ⅶ 2166 罗马数字七 ⅻ 217B 小罗马数字十二

它会产生以下结果:

@ 0040 广告在 © 00a9 版权标志 å 212b 埃符号 ⒜ 249c 带括号的拉丁文小写字母 a ⓐ 24b6 带圆圈的拉丁文大写字母 a Ⓐ 24d0 带圆圈的拉丁文小写字母 a a ff21 全角拉丁文大写字母 a A ff41 全角拉丁文小写字母 a ⓒ 24b8 带圆圈的拉丁文大写字母 c Ⓒ 24d2 带圆圈的拉丁文小写字母 c dz 01f1 拉丁文大写字母 dz dz 01f2 拉丁文大写字母 d 和小写字母 z DZ 01f3 拉丁文小写字母 dz Ⅲ 2172 小罗马数字三 s 0053 拉丁文大写字母 s S 0073 拉丁文小写字母 s S 017f 拉丁文小写字母长 s ⒮ 24ae 带括号的拉丁文小写字母 s ⓢ 24c8 带圆圈的拉丁文大写字母 s Ⓢ 24e2 带圆圈的拉丁文小写字母 s ꞅ a784 拉丁文大写字母 insular s Ꞅ a785 拉丁文小写字母 insular s SS 00df 拉丁文小写字母 s ß 1e9e 拉丁文大写字母 s ⅶ 2166 罗马数字七 Ⅻ 217b 小罗马数字十二

使用第一个函数(在该集合中)唯一不同的部分是 dz 序列将看起来像这样:

dz 01f1 拉丁文大写字母 dz DZ 01f2 拉丁文大写字母 d 和小写字母 z DZ 01f3 拉丁文小写字母 dz

您不想只使用上限或下限测试的原因是因为您做了不必要的工作,因为有很多大小写代码点在大小写映射时不会改变大小写。例如,所有这些都是大小写的代码点,但无论是大写还是小写都不会改变:

ª 00AA 女性序数指标 ᴬ 1D2C 修饰字母大写 A ᴀ 1D00 拉丁字母小写字母 A ℂ 2102 大写字母 C ᴰ 1D30 修饰字母大写 D ʣ 02A3 拉丁文小写字母 DZ 图 ʤ 02A4 拉丁文小写字母 DEZH DIGRAPH ℇ 2107 欧拉常数 ɘ 0258 反转的拉丁文小写字母 E ɞ 025E 拉丁文小写字母 闭 反 开 E ℊ 210A 脚本小 G ɡ 0261 拉丁文小写字母脚本 G ɢ 0262 拉丁字母小写字母 G ʰ 02B0 修饰字母小 H ℋ 210B 脚本大写字母 H ℎ 210E 普朗克常数 ℹ 2139 信息源 ʲ 02B2 修饰字母小 J ℳ 2133 脚本大写字母 M º 00BA 阳性序数指标 ɸ 0278 拉丁文小写字母 PHI ĸ 0138 拉丁文小写字母 KRA ʏ 028F 拉丁字母小写字母 Y ℼ 213C 双头小派

因此您会检测到它们是大写还是小写,然后调用逆映射函数,然后发现根本没有任何变化。我想,何必呢?

【讨论】:

  • ß 没有大写成 是谁的错?
  • @daxim:Unicode将U+DF的大写映射定义为U+53 U+53;也就是说,对于 ß 到大写到 SS。这可以在unicore/ 目录中的文件SpecialCasing.txt 中找到。 U+00DF ‹ß› \N{LATIN SMALL LETTER SHARP S}\p{Age:1.1},而 U+1E9E ‹ẞ› \N{LATIN CAPITAL LETTER SHARP S}\p{Age:5.1}。你知道,casemapping 转换的往返从未得到保证。考虑一下 U+3C3 σ 和 U+3C2 ς 如何在大写时都变成 U+3A3 Σ,但同样的 U+3A3 Σ 小写时仅变为 U+3C3 σ。类似的例子不胜枚举。
猜你喜欢
  • 2017-01-26
  • 1970-01-01
  • 2016-02-24
  • 1970-01-01
  • 1970-01-01
  • 2014-02-15
  • 2022-01-08
  • 2013-09-21
  • 2020-12-29
相关资源
最近更新 更多