程序员,
我想逐行读取由记事本创建的Unicode(UTF-8)文本文件,我不想在屏幕上显示Unicode字符串,我只想阅读并比较字符串!。
此代码逐行读取ANSI文件,并比较字符串
逐行阅读test_ansi.txt
如果line =“b”打印“YES!”
否则打印“NO!”
#include <stdio.h>
int main()
{
char *inname = "test_ansi.txt";
FILE *infile;
char line_buffer[BUFSIZ]; /* BUFSIZ is defined if you include stdio.h */
char line_number;
infile = fopen(inname, "r");
if (!infile) {
printf("\nfile '%s' not found\n", inname);
return 0;
}
printf("\n%s\n\n", inname);
line_number = 0;
while (fgets(line_buffer, sizeof(line_buffer), infile)) {
++line_number;
/* note that the newline is in the buffer */
if (strcmp("b\n", line_buffer) == 0 ){
printf("%d: YES!\n", line_number);
}else{
printf("%d: NO!\n", line_number,line_buffer);
}
}
printf("\n\nTotal: %d\n", line_number);
return 0;
}
a
b
c
gcc -o read_ansi_line_by_line read_ansi_line_by_line.c
test_ansi.txt
1: NO!
2: YES!
3: NO!
Total: 3
现在我需要读取由记事本创建的Unicode(UTF-8)文件,经过6个多月我没有在C中找到任何好的代码/库可以读取以UTF-8编码的文件!,我不知道确切原因,但我认为标准C不支持Unicode!
读取Unicode二进制文件OK!,但问题是二进制文件中已经创建的二进制文件!这意味着如果我们想要读取由记事本创建的Unicode(UTF-8)文件,我们需要从UTF-8文件到BINARY文件!
此代码将Unicode字符串写入二进制文件,注意C文件以UTF-8编码并由GCC编译
将Unicode char“ب”写入test_bin.dat
#define UNICODE
#ifdef UNICODE
#define _UNICODE
#else
#define _MBCS
#endif
#include <stdio.h>
#include <wchar.h>
int main()
{
/*Data to be stored in file*/
wchar_t line_buffer[BUFSIZ]=L"ب";
/*Opening file for writing in binary mode*/
FILE *infile=fopen("test_bin.dat","wb");
/*Writing data to file*/
fwrite(line_buffer, 1, 13, infile);
/*Closing File*/
fclose(infile);
return 0;
}
gcc -o create_bin create_bin.c
create test_bin.dat
现在我想逐行读取二进制文件并进行比较!
逐行读取test_bin.dat 如果line =“ب”打印“YES!” 否则打印“不!”
#define UNICODE
#ifdef UNICODE
#define _UNICODE
#else
#define _MBCS
#endif
#include <stdio.h>
#include <wchar.h>
int main()
{
wchar_t *inname = L"test_bin.dat";
FILE *infile;
wchar_t line_buffer[BUFSIZ]; /* BUFSIZ is defined if you include stdio.h */
infile = _wfopen(inname,L"rb");
if (!infile) {
wprintf(L"\nfile '%s' not found\n", inname);
return 0;
}
wprintf(L"\n%s\n\n", inname);
/*Reading data from file into temporary buffer*/
while (fread(line_buffer,1,13,infile)) {
/* note that the newline is in the buffer */
if ( wcscmp ( L"ب" , line_buffer ) == 0 ){
wprintf(L"YES!\n");
}else{
wprintf(L"NO!\n", line_buffer);
}
}
/*Closing File*/
fclose(infile);
return 0;
}
test_bin.dat
YES!
这种方法非常长!并且没有力量(我是软件工程的初学者)
请任何人知道如何阅读Unicode文件? (我知道这不容易!) 请任何人知道如何将Unicode文件转换为二进制文件? (简单方法) 请任何人知道如何在二进制模式下读取Unicode文件? (我不确定)
谢谢。
答案 0 :(得分:6)
UTF-8的一个不错的属性是不需要解码才能进行比较。无论您是先解码,strcmp返回的顺序都是相同的。所以只需将其作为原始字节读取并运行strcmp。
答案 1 :(得分:5)
我找到了解决问题的方法,我想与任何有兴趣在C99中阅读UTF-8文件的人分享解决方案。
void ReadUTF8(FILE* fp)
{
unsigned char iobuf[255] = {0};
while( fgets((char*)iobuf, sizeof(iobuf), fp) )
{
size_t len = strlen((char *)iobuf);
if(len > 1 && iobuf[len-1] == '\n')
iobuf[len-1] = 0;
len = strlen((char *)iobuf);
printf("(%d) \"%s\" ", len, iobuf);
if( iobuf[0] == '\n' )
printf("Yes\n");
else
printf("No\n");
}
}
void ReadUTF16BE(FILE* fp)
{
}
void ReadUTF16LE(FILE* fp)
{
}
int main()
{
FILE* fp = fopen("test_utf8.txt", "r");
if( fp != NULL)
{
// see http://en.wikipedia.org/wiki/Byte-order_mark for explaination of the BOM
// encoding
unsigned char b[3] = {0};
fread(b,1,2, fp);
if( b[0] == 0xEF && b[1] == 0xBB)
{
fread(b,1,1,fp); // 0xBF
ReadUTF8(fp);
}
else if( b[0] == 0xFE && b[1] == 0xFF)
{
ReadUTF16BE(fp);
}
else if( b[0] == 0 && b[1] == 0)
{
fread(b,1,2,fp);
if( b[0] == 0xFE && b[1] == 0xFF)
ReadUTF16LE(fp);
}
else
{
// we don't know what kind of file it is, so assume its standard
// ascii with no BOM encoding
rewind(fp);
ReadUTF8(fp);
}
}
fclose(fp);
}
答案 2 :(得分:2)
fgets()可以解码UTF-8编码的文件。像这样更改你的代码:
infile = fopen(inname, "r, ccs=UTF-8");
答案 3 :(得分:2)
在本文中,编写了一个编码和解码例程 它解释了如何编码unicode:
http://www.codeguru.com/cpp/misc/misc/multi-lingualsupport/article.php/c10451/
可以轻松调整为C. 只需编码您的ANSI或解码UTF-8字符串并创建一个字节 比较
编辑:在OP之后说从C ++重写函数太难了 这是一个模板:
需要什么:
+释放分配的内存(或等到过程结束或忽略它)
+添加4字节功能
+告诉我short和int不能保证长2和4个字节(我知道,但是
C真的很蠢!)最后是
+找一些其他错误
#include <stdlib.h>
#include <string.h>
#define MASKBITS 0x3F
#define MASKBYTE 0x80
#define MASK2BYTES 0xC0
#define MASK3BYTES 0xE0
#define MASK4BYTES 0xF0
#define MASK5BYTES 0xF8
#define MASK6BYTES 0xFC
char* UTF8Encode2BytesUnicode(unsigned short* input)
{
int size = 0,
cindex = 0;
while (input[size] != 0)
size++;
// Reserve enough place; The amount of
char* result = (char*) malloc(size);
for (int i=0; i<size; i++)
{
// 0xxxxxxx
if(input[i] < 0x80)
{
result[cindex++] = ((char) input[i]);
}
// 110xxxxx 10xxxxxx
else if(input[i] < 0x800)
{
result[cindex++] = ((char)(MASK2BYTES | input[i] >> 6));
result[cindex++] = ((char)(MASKBYTE | input[i] & MASKBITS));
}
// 1110xxxx 10xxxxxx 10xxxxxx
else if(input[i] < 0x10000)
{
result[cindex++] = ((char)(MASK3BYTES | input[i] >> 12));
result[cindex++] = ((char)(MASKBYTE | input[i] >> 6 & MASKBITS));
result[cindex++] = ((char)(MASKBYTE | input[i] & MASKBITS));
}
}
}
wchar_t* UTF8Decode2BytesUnicode(char* input)
{
int size = strlen(input);
wchar_t* result = (wchar_t*) malloc(size*sizeof(wchar_t));
int rindex = 0,
windex = 0;
while (rindex < size)
{
wchar_t ch;
// 1110xxxx 10xxxxxx 10xxxxxx
if((input[rindex] & MASK3BYTES) == MASK3BYTES)
{
ch = ((input[rindex] & 0x0F) << 12) | (
(input[rindex+1] & MASKBITS) << 6)
| (input[rindex+2] & MASKBITS);
rindex += 3;
}
// 110xxxxx 10xxxxxx
else if((input[rindex] & MASK2BYTES) == MASK2BYTES)
{
ch = ((input[rindex] & 0x1F) << 6) | (input[rindex+1] & MASKBITS);
rindex += 2;
}
// 0xxxxxxx
else if(input[rindex] < MASKBYTE)
{
ch = input[rindex];
rindex += 1;
}
result[windex] = ch;
}
}
char* getUnicodeToUTF8(wchar_t* myString) {
int size = sizeof(wchar_t);
if (size == 1)
return (char*) myString;
else if (size == 2)
return UTF8Encode2BytesUnicode((unsigned short*) myString);
else
return UTF8Encode4BytesUnicode((unsigned int*) myString);
}
答案 4 :(得分:2)
我知道我很糟糕......但你甚至不考虑BOM!这里的大多数例子都会失败。
编辑:
字节顺序标记在文件的beginnig处是几个字节,可用于标识文件的编码。有些编辑添加它们,很多时候它们只是以各种方式破解(我记得因为这个问题而在几分钟内解决PHP头问题)。
一些RTFM: http://en.wikipedia.org/wiki/Byte_order_mark http://blogs.msdn.com/oldnewthing/archive/2004/03/24/95235.aspx What is XML BOM and how do I detect it?
答案 5 :(得分:0)
只是为了解决BOM参数。这是来自记事本的文件
[paul@paul-es5 tests]$ od -t x1 /mnt/hgfs/cdrive/test.txt
0000000 ef bb bf 61 0d 0a 62 0d 0a 63
0000012
在开始时使用BOM
我个人认为不应该有BOM(因为它是一个字节格式),但那不是重点