【问题标题】:Matching russian vowels in C++在 C++ 中匹配俄语元音
【发布时间】:2013-05-16 14:38:16
【问题描述】:

我想编写一个函数,如果给定字符是俄语元音,则返回 true。但是我得到的结果对我来说很奇怪。这是我到目前为止所得到的:

#include <iostream>

using namespace std;

bool is_vowel_p(char working_char)
// returns true if the character is a russian vowel
{
    string matcher = "аяё×эеуюыи";

    if (find(matcher.begin(), matcher.end(), working_char) != matcher.end())
        return true;
    else
        return false;
}


void main()
{
    cout << is_vowel_p('е') << endl; // russian vowel
    cout << is_vowel_p('Ж') << endl; // russian consonant

    cout << is_vowel_p('D') << endl; // latin letter
}

结果是:

1
1
0

对我来说有什么奇怪的。我期望得到以下结果:

1
0
0

似乎有某种我还不知道的内部机制。我起初对如何修复此功能以使其正常工作感兴趣。其次,那里发生了什么,我得到了这个结果。

【问题讨论】:

  • 可能只有我,但我不认为Ж包含在аяё×эеуюыи
  • @Renan:这就是为什么“0”是第二个预期结果。
  • 与您的问题无关,但您可以将函数缩短一点:return find(matcher.begin(), matcher.end(), working_char) != matcher.end(); 您也可以将matcher 字符串标记为const,因为它永远不会改变,甚至可能是static .
  • 代码工作正常:ideone.com/CBJoD4(尽管您的字符串匹配器不正确。它应该是“аяёоэеуюыи”)
  • @icepack:它不能正常工作;我怀疑编译器会将超出范围的字符转换为恰好给出预期结果的值,而 OP 没有。

标签: c++ cyrillic


【解决方案1】:

stringchar 只保证代表基本字符集中的字符 - 不包括西里尔字母。

使用wstringwchar_t,并在字符串和字符文字前添加L 以表明它们使用宽字符,应该允许您使用这些字母。

此外,为了可移植性,您需要为find 包含&lt;algorithm&gt;,并为main 提供int 的返回类型。

【讨论】:

  • 如果系统默认语言环境是西里尔文 (CP1251),它会这样做。在俄罗斯,这是一个相当安全的假设。但否则很脆。
  • @SevaAlekseyev:确实(假设字符串文字使用固定的 8 位编码,例如不是 UTF-8);正如我所说,它只是保证支持基本集合(拉丁字母、数字和一些标点字符)。
  • 其实很有趣。在这个例子中,布局是否是西里尔文并不重要。由于输入是char,因此任何高于 7 位的内容都会被转换为它。
  • @icepack:不,char 必须至少为 8 位,并且不会被截断。因此,如果您知道字符串使用固定大小的 8 位表示,包括您感兴趣的字符,那么它应该可以工作。大概。我自己会坚持使用 Unicode。
  • 对不起,改变了我原来的评论。我的意思是任何大于 128 的值都会导致有符号整数溢出(并且可能会环绕,但它确实是 UB)
【解决方案2】:

C++ 源代码是 ASCII。您正在输入 Unicode 字符。使用 8 位值进行比较。我敢打赌其中一个元音满足以下条件:-

vowel & 255 == (code point for 'Ж') & 255

您需要使用 unicode 函数来执行此操作,而不是 ASCII 函数,即使用需要 wchar_t 值的函数。此外,请确保您的编译器可以解析非 ASCII 元音字符串。使用 MS VC,编译器需要:-

L"аяё×эеуюыи" or TEXT("аяё×эеуюыи")

后者是一个宏,在编译时使用 unicode 支持添加 L

将代码转换为使用 wchar_t,它应该可以工作。

【讨论】:

  • @icepack 没有“俄罗斯 ASCII”。 ASCII 是 7 位编码。您可能是指俄语代码页。
  • 俄语字母以俄语 ASCII 布局呈现。这是正确的方向,但 Ж 出现在 8 位 ASCII 表中。请参阅@MikeSeymour 答案和 cmets
  • @milleniumbug 完整的 ASCII 表是 8 位的。第二部分用处不大,但肯定存在。
  • @icepack No. ASCII 是 7 位编码。第二部分由代码页定义。 CP1251 是俄语代码页。
  • @milleniumbug 8 位 ASCII 表的第二部分由代码页定义。这并不意味着它不属于 ASCII
【解决方案3】:

locale.h中非常有用的函数

setlocale(LC_ALL, "Russian");

在程序的开头将其过去。 示例:

#include <stdio.h>
#include <locale.h>

void main()
{
    setlocale(LC_ALL, "Russian");

    printf("Здравствуй, мир!\n");//Hello, world!
}

【讨论】:

    【解决方案4】:

    确保您的系统默认区域设置为俄语,并确保您的文件保存为代码页 1251(西里尔文/Windows)。如果它保存为 Unicode,这将永远无法工作。

    系统默认语言环境是非 Unicode 兼容程序使用的语言环境。它位于控制面板中的区域设置下。

    或者,重写以使用 wstringwchar_tL"" 字符串/字符文字。

    【讨论】:

    • 你的编译器很可能是 Unicode 兼容的。这与解析非 Unicode 源文件时需要 a 语言环境这一事实完全无关。
    猜你喜欢
    • 2014-11-21
    • 2018-08-25
    • 1970-01-01
    • 1970-01-01
    • 2014-04-21
    • 2010-10-23
    • 1970-01-01
    • 2012-01-14
    • 1970-01-01
    相关资源
    最近更新 更多