更新某些扫描仪代码以使用ICU时的问题

时间:2011-05-29 03:57:39

标签: c utf-8 icu

我正在研究一种基本的手工编码词法扫描仪,并希望支持UTF-8输入(它不再是1970年了!)。输入字符一次从stdin或一个文件读取并推入缓冲区,直到看到空格等。我考虑为fgetc()编写自己的包装器,而不是返回char[]构成UTF-8字符的字节组合并将结果作为字符串...它很容易,但会变成一个滑坡。我宁愿不浪费时间重新发明轮子,而是使用现有的,经过测试的库,如ICU。所以现在我有一个非UTF-8支持代码,可与fgetc()isspace()strcmp()等一起使用,我正在尝试更新以使用ICU。这是我第一次尝试使用ICU并阅读文档并试图通过Google代码搜索查找使用示例,但仍然存在一些混淆点,我希望有人能够澄清。

u_fgetc()函数返回UCharu_fgetcx()返回UChar32 ...文档建议使用u_fgetcx()来读取代码点,这就是我的意思从...开始。我保持与上面相同的方法,但我将UChar32推入缓冲区而不是char s。

  • 将字符与已知值进行比较的正确方法是什么?最初我能够if (c == '+')检查加号是否是从输入中获取的。当cUChar32时,GCC不会抱怨(这是UChar32char之间的比较),但这是否合适?

  • 我能够使用strcmp()将缓冲的字符与已知值进行比较,例如if ((strcmp(buf, "else") == 0)。 ICU提供了u_strcmp(),我想我可能需要使用U_STRING_DECLU_STRING_INIT宏来指定已知文字,但我不确定。文档显示它们导致UChar[],但我认为我需要UChar32[] ...而且我不确定如何正确使用它们。欢迎任何指导。

  • 在阅读了一系列数字字符后,我一直用strtol()转换它们,所以我可以使用它们。 ICU是否提供类似功能,因为我现在转换UChar32[]

2 个答案:

答案 0 :(得分:5)

UChar用于保存代码单元,而UChar32用于保存代码点。如果您的输入保留在Basic Multilingual Plane(BMP)上,则UChar就足够了,而且大多数ICU功能都会在UChar[]上运行。

强烈推荐的阅读是ICU User Guide,它解释了大多数内部和最佳实践。

  • 将Unicode字符变量与已知值进行比较的正确方法是什么? 字符(或UCharUChar32)只是具有一定宽度和符号的另一个整数类型,并且可以与其他整数类型进行比较,具有通常的警告和限制。至于定义字符值,C99(第6.4.3章)提供通用字符名称表示法:\u后跟四个十六进制数字,或{{1}后跟八个十六进制数字,指定ISO / IEC 10646“短标识符”。低于0x00a0的区域(除了0x0024 \U,0x0040 '$'和0x0060(反引号)之外的区域是保留的(但可以通过将简单字符常量转换为'@'来表示)。还保留是从0xd800到0xdfff的范围(供UTF-16使用)。

  • 如何定义Unicode字符串文字? UCharU_STRING_DECL确实是您正在寻找的。 (如上所述,ICU主要在U_STRING_INIT上运行。)如果您使用C ++而不是C,UNICODE_STRING_SIMPLE(可选地后跟UChar[]再次产生getTerminatedBuffer())提供了更方便的定义Unicode字符串文字的方法。

  • 如何将表示数字的Unicode字符串转换为该数字的值? unum_parse()及其UChar[]中的兄弟会帮助您。

答案 1 :(得分:2)

  1. PLUS SIGN的Unicode值为U + 002B,“+”的正常(Latin-1)值也为0x2B(053,43)。您编写的内容足够安全,代码集基于ASCII或ISO-8859-x。 C99标准提供了\u0123\U00102345形式的Unicode(通用字符名称)(带有4和8个十六进制数字),但规定您不能指定小于\u00A0的值,例如为\u002B。所以,我认为你写的是正确的。

    但是,您可以使用enum(例如

    )来保护自己未来的焦虑
     enum { PLUS_SIGN = '+' };
    

    在适当的标题中定义,并在需要文字加号时使用。这样,如果你的假设(和我的假设)是错误的,你就有一个地方可以编辑 - 标题。

    我注意到Strings与ICU的页面表明在应用程序中使用UTF-32是不寻常的。

  2. 在纯C中,您可能会使用wcscmp(buf, L"else"),假设系统上的wchar_t等同于uint32_t和/或UChar32。似乎有办法使用UnicodeStringUNICODE_STRING("...")后跟ToUTF32()来创建UTF-32字符串。可能还有更简洁的方法。

  3. 有'格式化'类可以处理格式化和解析。您可能会使用从NumberFormat类派生的类。