【问题标题】:How does s[i]^=32 convert upper to lower case?s[i]^=32 如何将大写转换为小写?
【发布时间】:2023-03-14 08:51:01
【问题描述】:
int main()
{
    string s;
    cout << "enter the string :" << endl;
    cin >> s;
    for (int i = 0; i < s.length(); i++)
        s[i] ^= 32;
    cout << "modified string is : " << s << endl;
    return 0;
}

我在stackoverflow上看到了将大写转换为小写的这段代码。

但是s[i] = s[i]^32这行我听不懂。

它是如何工作的?

【问题讨论】:

  • 不用担心看不懂。它不是便携式的,不应该使用。
  • 即使仅适用于 ASCII,它也会切换大小写并对字母以外的字符造成不良影响。
  • @MarkRansom 当然,如果您知道您的用例只会是 ASCII,那么这不是问题,但应该记录在代码中。当您对 C++ 标准没有限制的情况下的某些情况进行限制时,您应该记录下来。我也不认为我的说法有任何夸张。 C++ 甚至不需要使用 ASCII 或字符是连续的。
  • @MarkRansom:当然,知识无伤大雅。尽管如此,在过去,很多事情都不同了,并不是所有事情都变得更好。

标签: c++ string uppercase lowercase


【解决方案1】:

它是如何工作的?

让我们看看 ASCII 值 'A':

'A' 是二进制1000001

与 32 异或(二进制 100000

产生没有设置高位字符指示位的任何值:

1000001 异或 100000 = 1100001 == 'a' ASCII 格式。


任何健全且可移植的 c 或 c++ 应用程序都应使用 tolower():

int main()
{
    string s;
    cout<<"enter the string :"<<endl;
    cin>>s;
    for (int i=0;i<s.length();i++) s[i] = tolower( (unsigned char)s[i] );
                                     // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    cout<<"modified string is : "<<s<<endl;
    return 0;
}

s[i]=s[i]^32(货物崇拜)魔法依赖于 ASCII table 特定映射到数字 char 值。

还有其他 char 代码表,例如EBCDIC , 其中

 s[i]=s[i]^32

该方法严重无法检索相应的小写字母。


std::ctype::tolower() 的参考文档页面中显示了转换为小写字符的更复杂的 c++ 版本。

【讨论】:

  • ctype 是类模板,不是类,tolower() 是非静态成员函数。
  • @Barry THX 指出了这一点。固定回退到直 c 版本。 (好吧,现在有点使 “任何理智且可移植的 c++ 应用程序” 无效)。
  • 毕竟这是C++。为什么我们没有 three different functions 命名为 tolower()。如果算上ctype 的范围重载,我猜是 4。
  • 可移植代码为s[i] = tolower( (unsigned char)s[i] )s[i] = tolower( s[i], std::locale() );
  • ^@M.M 采用了你的第一个版本。
【解决方案2】:

在 C++ 中,与其前身 C 一样,char 是一种数字类型。毕竟这就是字符在硬件上的表示方式,而这些语言不会对您隐藏这一点。

在 ASCII 中,字母的有用属性是大写和小写字母之间的区别是一个二进制位:第 5 位(如果我们从 0 开始从右侧开始编号)。

大写A由字节0b01000001(十六进制0x41)表示,小写a由字节0b01100001(十六进制0x61)表示。请注意,大写和小写 A 之间的唯一区别是第五位。这种模式从 B 一直延续到 Z。

所以,当您对代表 ASCII 字符的数字执行 ^= 32(顺便说一下,它是 2 的 5 次方)时,所做的就是切换第 5 位 - 如果它是 0,它将变为 1,反之亦然,这会将字符从大写变为小写,反之亦然。

【讨论】:

  • ...如果您的 C++ 实现使用 ASCII。
  • @ChristianHackl 我专门将 ASCII 命名为我在回答中所说的字符集(因为它与 OP 的问题相同)
  • 是的,但您没有提到您的 C++ 实现可能根本不使用 ASCII。
  • PLZZ 给我一个例子,我可以很容易理解它
  • @RashedSami 这个答案一个例子。你在评论之前读过它吗?
【解决方案3】:

^=exclusive-or 赋值运算符。 32 是二进制的 100000,所以^= 32 切换目标中的第五位。在 ASCII 中,小写字母和大写字母相隔 32 个位置,因此这会将小写转换为大写,反之亦然。

但它仅适用于 ASCII,例如不适用于 Unicode,并且仅适用于字母。要编写可移植的 C++,你不应该假设字符编码是 ASCII,所以请不要使用这样的代码。 @πάντα ῥεῖs 的回答显示了一种正确的方法。

【讨论】:

  • 永远不要使用这样的代码。
  • 它只适用于字母字符。它会对别人做出疯狂的事情。
  • @magic-sudo:除了 a-z 和 A-Z,还有很多 ASCII 字符。
  • 这可能会导致以后难以追踪的错误。
  • @alain:嗯,这就是我的意思。在暗示不能假设 ASCII 之前,您谈到了 32 个位置。对于初学者来说,这句话听起来好像 “大小写字母相隔 32 个位置” 在 C++ 中是普遍正确的。
猜你喜欢
  • 1970-01-01
  • 2011-07-21
  • 1970-01-01
  • 2022-01-24
  • 2023-03-19
  • 2013-02-04
  • 2011-10-29
  • 1970-01-01
  • 2016-02-24
相关资源
最近更新 更多