为什么我的程序用2个空格替换字符?

时间:2017-10-05 17:19:47

标签: c

我的程序任务是删除和字符< 32和> 127 ascii值,但输出显示我2个空格。 示例:

输入:préféré

预期产出:pr f r

我的输出:pr(2个空格)f(2个空格)r(2个空格)

#include<stdio.h>
#include<string.h>
int main() {
  unsigned char str[100];
  unsigned char space = ' ';
  fgets(str,100,stdin);
  int i=0;
  int length = strlen(str);
  while(i<length)
  {
    if( ((int)str[i]>32) && ((int)str[i]<127) )
    {
      i++;
      continue;
    }
    else
    {
        str[i]=space;
    }
    i++;
  }
  printf("%s\n",str);
}

2 个答案:

答案 0 :(得分:3)

可能是因为像é(非ASCII)这样的字符占用了2个字节。因此,对于每个é,您的循环运行两次,因此放置2个空格代替é

在相关说明中,使用isascii()中的<ctype.h>来测试ASCII字符。

答案 1 :(得分:1)

如果您想以便携式,区域设置感知的方式解决这个看似简单的问题会变得非常复杂。另一方面,如果已知原始文本以UTF-8编码,则解决方案非常简单,特别是如果您不需要检测无效的UTF-8序列。

UTF-8编码中可能的字节值分为四组:

  • 单字节US-ASCII字符:字节值0x00到0x7F,包括端点。

  • 多字节字符中的第一个字节:值0xC2到0xF4(含)。

  • 多字节字符的尾随字节:值0x80到0xBF,包括端值。

  • 不能出现在任何UTF-8代码中的字节:其他所有内容(0xC0,0xC1和0xF5及更高版本)。

因此,每个字符在前两组值中只包含一个字节。所以一个简单的策略就是删除后两组中的字节:

unsigned char* out = str;
for (unsigned char* scan = str; *scan; ++scan) {
  if (*scan >= 0x20 && *scan < 0x7F) {
    // Pass through printable ascii characters
    *out++ = *scan;
  }
  else if (*scan < 0x80 || (*scan >= 0xC2 && *scan <= 0xF4)) {
    // Replace non-printable ascii characters and lead UTF-8 bytes with space
    *out++ = ' ';
  }
  // Anything else is ignored and will be overwritten.
}
*out = 0;

我从这个答案中删除了所谓的符合标准的可移植代码,因为它太复杂了,并且生成的代码不太可能适用。通常,不保证对实用程序的输入符合当前语言环境的多字节编码:例如,至少可以想象输入是wchar的向量(例如,以UTF编码的文件)在具有32位wchar的系统上32。或者输入确实是UTF-8,但当前的语言环境是ISO-8859-7,这是一个单字节编码。没有通用的便携方式将wchar(或多字节序列)转换为“Ascii”,以便测试给定字符是否是代码范围0x20到0x7F中的ASCII可打印字符之一。 (如果这一段似乎是难以理解的术语,那将有助于解释为什么编写和记录便携式解决方案很困难。)