我的程序任务是删除和字符< 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);
}
答案 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可打印字符之一。 (如果这一段似乎是难以理解的术语,那将有助于解释为什么编写和记录便携式解决方案很困难。)