【问题标题】:Return proper umlaut character from pointer to char?从指向char的指针返回正确的变音符号?
【发布时间】:2014-12-17 13:12:51
【问题描述】:

我正在尝试从旧的 FAME 数据库文件中获取正确的字符描述。基本上这是可行的,但是变音符号等没有正确打印。基本上,R Package FAME 中包含的以下 C 函数与其说是 R 问题,不如说是 C 问题。

void fameWhat(int *status, int *dbkey, char **objnam, int *class,
         int *type, int *freq, int *basis, int *observ,
         int *fyear, int *fprd, int *lyear, int *lprd, 
         int *obs, int *range, 
         int * getdoc, char **desPtr, char **docPtr){
 /* Get info about an object. Note that range should be an int[3] on input */
int cyear, cmonth, cday, myear, mmonth, mday;
int i;
char fdes[256], fdoc[256];

if(*getdoc){
if(strlen(*desPtr) < 256 || strlen(*docPtr) < 256){
  *status = HBNCHR;
  return;
}
for(i = 0; i < 255; ++i) fdes[i] = fdoc[i] = ' ';
}
fdes[255] = fdoc[255] =  '\0';

cfmwhat(status, *dbkey, *objnam, class, type, freq, basis, observ,
      fyear, fprd, lyear, lprd, &cyear, &cmonth, &cday, &myear,
      &mmonth, &mday, fdes, fdoc);
if(*getdoc){
  strncpy(*desPtr, fdes, 256);
  strncpy(*docPtr, fdoc, 256);
}
if(*status == 0 && *class == HSERIE)
  cfmsrng(status, *freq, fyear, fprd, lyear, lprd, range, obs);
return;
}

我觉得由于指向描述的指针 desPtr 的指针是 char 类型的事实,当从 R 调用此函数并在 R 控制台中显示结果时,我没有得到任何正确的变音符号.我有一种预感,FAME 是 Latin-1 编码的。 R 是 UTF-8。例如,对于ä,我得到\U3e34653c

那么有没有办法在 C 中完成它并将正确的值传递给 R 或者我应该在 R 中搜索和替换?

注意:我看过这个帖子 Using Unicode in C++ source code 和这个 How to use utf8 character arrays in c++?

【问题讨论】:

    标签: c r pointers utf-8 char


    【解决方案1】:

    您似乎有多个堆叠的编码/解码。首先,您是如何为单个字符“获得”如此长的 Unicode 值的?

    该长代码的原始十六进制到 ASCII 转换是 &gt;4E&lt;&lt;E4&gt;(取决于字节序),而后者被解释为带括号的十六进制值,是您期望的 ähttp://www.fileformat.info/info/unicode/char/00E4/index.htm,这是一个有效的 Latin-1 编码。

    从这种编码格式转换为 UTF8 相对简单,尽管我不确定将这种代码粘贴到现有例程的何处。作为一个示例独立程序:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main (void)
    {
        char input[] = "a sm<F6>rg<E5>sbord of <code>";
        char *sourceptr, *destptr, *endptr;
        int latin1;
    
        sourceptr = input;
        destptr = input;
        while (*sourceptr)
        {
            if (*sourceptr == '<')
            {
                latin1 = strtol (sourceptr+1, &endptr, 16);
                if (endptr && *endptr == '>' && latin1 > 127 && latin1 <= 255)
                {
                /*  printf ("we saw hex code %xh\n", latin1); */
                /*  Quick-and-dirty converting to UTF8: */
                    *destptr = (char)(0xc0 | ((latin1 & 0xc0) >> 6));
                    destptr++;
                    *destptr = (char)(0x80 | (latin1 & 0x3f));
                    destptr++;
                    sourceptr = endptr+1;
                    continue;
                }
            }
            *destptr = *sourceptr;
            sourceptr++;
            destptr++;
        }
        *destptr = 0;
        printf ("output: %s\n", input);
    
        return 0;
    }
    

    这会扫描输入字符串中的&lt;,后跟一个有效的十六进制代码(假设它是Latin-1,因此限制为80..FF)和另一个&gt;。找到后,它会以 UTF8 格式插入字符。无法识别的序列按原样复制。

    【讨论】:

    • +1 用于文件格式链接。我是怎么得到这么长的字符串的。好问题。旧的 db FAME 有一个 C 接口。所以我使用上面的函数来访问数据库并从中获取描述。我使用 R 访问该函数,它再次可以所有 C 函数并以交互方式返回结果,因为 R 是一种脚本语言。除了这些变音符号之外,这通常非常有效。我只是不知道为什么我会得到 iconv 等无法修复的东西。
    • @Matt:也许您需要扫描函数中的输入字符串以获取这种简单的编码并将找到的十六进制序列转换为正确的 UTF8?
    • 通过扫描意味着修改C函数或者更确切地说,或者更确切地说是过程?能给我举个例子吗?我是这里的数据/统计/R 人 :)
    • @Matt:我在答案中添加了一个基本的转换示例,但实际上我不知道将其插入现有函数的位置。也许其他人可以帮助你。
    • 非常感谢,我想我应该能够在我有时间尝试的时候尽快解决这个问题。我想我必须使用 C 直接访问数据库,然后让 C 在某处打印输出并查看结果。
    猜你喜欢
    • 2016-12-28
    • 2018-04-05
    • 2016-06-10
    • 1970-01-01
    • 1970-01-01
    • 2021-05-07
    • 2011-02-07
    • 1970-01-01
    • 2012-10-11
    相关资源
    最近更新 更多