如何从 C stdio.h getline() 替换/忽略无效的 Unicode/UTF8 字符?

2023-12-07

在Python上,有这个选项errors='ignore'为了openPython函数:

open( '/filepath.txt', 'r', encoding='UTF-8', errors='ignore' )

这样,读取包含无效 UTF8 字符的文件时,它们将被替换为空,即它们被忽略。例如,包含字符的文件Føö»BÃ¥r将被读作FøöBår.

如果一行作为Føö»BÃ¥r是用getline() from stdio.h,它将被读作Føö�Bår:

FILE* cfilestream = fopen( "/filepath.txt", "r" );
int linebuffersize = 131072;
char* readline = (char*) malloc( linebuffersize );

while( true )
{
    if( getline( &readline, &linebuffersize, cfilestream ) != -1 ) {
        std::cerr << "readline=" readline << std::endl;
    }
    else {
        break;
    }
}

我怎样才能使stdio.h getline()将其读作FøöBår代替Føö�Bår,即忽略无效的 UTF8 字符?

我能想到的一个压倒性的解决方案是迭代每行上的所有字符读取并构建一个新的readline没有任何这些字符。例如:

FILE* cfilestream = fopen( "/filepath.txt", "r" );
int linebuffersize = 131072;
char* readline = (char*) malloc( linebuffersize );
char* fixedreadline = (char*) malloc( linebuffersize );

int index;
int charsread;
int invalidcharsoffset;

while( true )
{
    if( ( charsread = getline( &readline, &linebuffersize, cfilestream ) ) != -1 )
    {
        invalidcharsoffset = 0;
        for( index = 0; index < charsread; ++index )
        {
            if( readline[index] != '�' ) {
                fixedreadline[index-invalidcharsoffset] = readline[index];
            } 
            else {
                ++invalidcharsoffset;
            }
        }
        std::cerr << "fixedreadline=" << fixedreadline << std::endl;
    }
    else {
        break;
    }
}

相关问题:

  1. 修复无效的 UTF8 字符
  2. 替换非 UTF8 字符
  3. python 替换unicode字符
  4. Python unicode:如何用空格替换无法使用utf8解码的字符?

你混淆了你所看到的和真实发生的事情。这getline函数不做任何字符替换。 [注1]

您看到替换字符 (U+FFFD) 是因为您的控制台在要求呈现无效的 UTF-8 代码时输出该字符。大多数控制台在 UTF-8 模式下都会这样做;也就是说,当前的语言环境是 UTF-8。

另外,说文件包含“字符Føö»BÃ¥r“充其量是不精确的。文件并不真正包含字符。它包含可以解释为字符的字节序列 - 例如,通过控制台或其他用户演示软件将它们呈现为字形 - 根据某种编码。不同不同的编码会产生不同的结果;在这种特殊情况下,您有一个由软件使用 Windows-1252 编码(或者大致相当于 ISO 8859-15)创建的文件,并且您使用 UTF-8 在控制台上渲染它。

这意味着 getline 读取的数据包含无效的 UTF-8 序列,但它(可能)不包含替换字符代码。根据您提供的字符串,它包含十六进制字符\xbb,这是海鸠(»)在 Windows 代码页 1252 中。

查找读取的字符串中所有无效的 UTF-8 序列getline(或任何其他读取文件的 C 库函数)需要扫描字符串,但不需要扫描特定的代码序列。相反,您需要一次解码一个 UTF-8 序列,查找无效的序列。这不是一个简单的任务,但是mbtowc函数可以提供帮助(如果您启用了 UTF-8 语言环境)。正如您将在链接的联机帮助页中看到的,mbtowc返回有效“多字节序列”(UTF-8 语言环境中的 UTF-8)中包含的字节数,或 -1 表示无效或不完整的序列。在扫描中,您应该以有效序列传递字节,或者删除/忽略开始无效序列的单个字节,然后继续扫描直到到达字符串末尾。

下面是一些经过简单测试的示例代码(C 语言):

#include <stdlib.h>
#include <string.h>

/* Removes in place any invalid UTF-8 sequences from at most 'len' characters of the
 * string pointed to by 's'. (If a NUL byte is encountered, conversion stops.)
 * If the length of the converted string is less than 'len', a NUL byte is
 * inserted.
 * Returns the length of the possibly modified string (with a maximum of 'len'),
 * not including the NUL terminator (if any).
 * Requires that a UTF-8 locale be active; since there is no way to test for
 * this condition, no attempt is made to do so. If the current locale is not UTF-8,
 * behaviour is undefined.
 */
size_t remove_bad_utf8(char* s, size_t len) {
  char* in = s;
  /* Skip over the initial correct sequence. Avoid relying on mbtowc returning
   * zero if n is 0, since Posix is not clear whether mbtowc returns 0 or -1.
   */
  int seqlen;
  while (len && (seqlen = mbtowc(NULL, in, len)) > 0) { len -= seqlen; in += seqlen; }
  char* out = in;

  if (len && seqlen < 0) {
    ++in;
    --len;
    /* If we find an invalid sequence, we need to start shifting correct sequences.  */
    for (; len; in += seqlen, len -= seqlen) {
      seqlen = mbtowc(NULL, in, len);
      if (seqlen > 0) {
        /* Shift the valid sequence (if one was found) */
        memmove(out, in, seqlen);
        out += seqlen;
      }
      else if (seqlen < 0) seqlen = 1;
      else /* (seqlen == 0) */ break;
    }
    *out++ = 0;
  }
  return out - s;
}

Notes

  1. 除了底层 I/O 库可能的行尾转换之外,这将用单个替换 CR-LF\n在像 Windows 这样的系统上,两个字符 CR-LF 序列用作行结束指示。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何从 C stdio.h getline() 替换/忽略无效的 Unicode/UTF8 字符? 的相关文章

随机推荐

  • 为什么循环顺序会影响二维数组迭代时的性能?

    下面是两个几乎相同的程序 除了我切换了i and j周围的变数 它们运行的 时间不同 有人可以解释为什么会发生这种情况吗 版本1 include
  • python/tkinter 绘图程序撤消函数

    我尝试在我的绘画程序中添加一个撤消功能 该功能从画布中删除对象 创建的每个对象都附加到堆栈中 我尝试了它 它可以工作 但屏幕不会仅在第一个撤消时更新 因此如果我绘制 3 条线然后我撤消什么也不会发生 当我一次又一次撤消时 第二行和第三行将被
  • 在 ImageView 上的 OnTouch 中返回 false,但事件仍然被消耗

    我在用ImageView onTouch 我返回 falseACTION MOVE但仍然是onTouch 事件被消耗 imageView setOnTouchListener new View OnTouchListener Overrid
  • 交换字符串中的大小写[重复]

    这个问题在这里已经有答案了 我正在尝试解决Hackerrank 中的这项挑战 它要求将所有小写字母转换为大写字母 反之亦然 我尝试使用以下代码 def swap case s length len s i 0 while length if
  • 从 R 闪亮的 selectInput 中过滤

    我试图让用户上传 csv 文件 然后获取该 csv 文件的一列 因子 并创建用户输入 以确定将为数据框选择该字段中的哪个唯一名称 因此 如果我有以下示例 data frame COURSE VALUE 1 A 7 2 C 2 3 C 2 4
  • 在 SSIS 中动态更改服务器名称

    我的 SSIS 包在开发周期 开发 QA 暂存和生产 期间会经历多个环境 因此我想使用 SSIS 中的配置来设置连接管理器中的服务器名称 这样我就不会不需要手动完成此操作 我读过有关使用 xml 配置文件 SQL 配置表和环境变量的内容 然
  • 谷歌地图:未捕获的类型错误:类型错误

    在几个页面上 我开始收到上述错误 但仅在 Chrome 中 这是一些简单的代码来演示该错误
  • 使用 boost::dynamic_bitset 作为键值对序列化 boost::bimap

    我有兴趣序列化boost bimap含有boost dynamic bitset这样我就可以保存它并在需要时加载回来 我已经尝试这样做 但遇到了很多错误 我随身携带的代码如下 Example program include
  • python 中的布尔值是可变的吗?

    我在 python 中有以下代码 def update request id success 0 try product Mattress objects get id id success 1 except Mattress DoesNo
  • C# 内存地址和变量

    在C 中 有没有办法 获取存储在a中的内存地址 引用类型变量 获取a的内存地址 多变的 EDIT int i int pi i 如何打印 pi 的十六进制值 对于 2 运算符的工作方式与 C 中相同 如果变量不在堆栈上 您可能需要使用fix
  • 从“SecKeychainFindGenericPassword”给出的“SecKeychainItemRef”中提取“用户名”?

    从这个问题 我知道你可以使用SecKeychainFindGenericPassword without用户名值 它仍然会返回给定服务的钥匙串项 但是我如何获取用户名呢 仅使用服务名称获取存储在钥匙串中的用户名 或者 您应该在哪里存储用户名
  • 是否可以将网页内容读入字符串中,以便我可以解析数据?

    我希望能够让我的 iPhone 将 URL 或者实际上是 url 指向的文件 加载到字符串中 我希望能够执行此操作的原因是这样我就可以解析字符串以查找标签并从中提取一些值 这些文件主要是网页 例如 html 或 asp 等 有人能给我一些提
  • 导出并发布 Typescript 中的所有类型和接口

    我正在尝试发布一个打字稿库 我不清楚如何公开所有类型和接口 这是我的设置 mylib src types mytypes ts index ts package json tsconfig json index ts import MyIn
  • Firefox - 删除未修饰复选框的边框

    我有一个复选框appearance none 这在 Chrome 中有效 但在 Firefox 中它留下了一个我无法删除的插入边框 我努力了border none已经 我这里有一个小提琴 http jsfiddle net jcJJ5 不幸
  • 根据 HTML 文本匹配产品价格

    我正在尝试在字符串上使用简单的正则表达式来获取定价信息 但是我的preg match all根本就是没有找到它应该找到的东西 我正在寻找例如 or 或者有时货币符号可能被编码为 HTML 实体 例如对于英镑 pound or 163 使用有
  • Django:在模型 save() 方法中返回序列化器 ValidationError

    我使用 django rest framework 在 Django 框架内创建 Rest API 并且可以返回任何validationError除了序列化器方法之外 但是 我想知道是否有可能返回错误save Django的方法model被
  • 将函数更改为 PDO

    这是我的api中使用的语句 这是第二个 result下面整个函数中的变量 如何将其更改为使用 PDO result query SELECT p IdPhoto p device token title p IdUser FROM phot
  • 如何在nodejs中向mysql查询回调传递参数

    我试图找出将自定义数据传递到查询调用以在回调中可用的正确方法 我在nodejs 中使用MySQL 库 所有最新版本 我调用了 connection query sql function err result 我找不到一种方法来 1 将自定义
  • 在父元素内将对象序列化为 XML

    我有一个 WPF C 程序 有时我需要将对象序列化为 XML 在其他地方 我一直在使用这个 TextWriter writer new StreamWriter xmlFilePath XmlSerializer xmlSerializer
  • 如何从 C stdio.h getline() 替换/忽略无效的 Unicode/UTF8 字符?

    在Python上 有这个选项errors ignore 为了openPython函数 open filepath txt r encoding UTF 8 errors ignore 这样 读取包含无效 UTF8 字符的文件时 它们将被替换