
程序代码:
/*
如果所有文件都很小,那就全部读到内存中
如果最大需要处理的文件都不算大,那就使用文件读写
如果大部分文件都很大,那就关闭文件读写缓存并分块读到内存,或使用内存映射,但这种情况要考虑块和块的边界
如果单词数目少,直接遍历
如果单词数目中等,使用红黑树、hash表等
如果单词数目很大,那就使用Trie字典树等
最麻烦的就是“单词”的定义,难在一般人不是语法学家,不知道英语中“全部的”单词分割规则。
比如 ming's 如果之前出现过 ming,则 ming's 要全部删除。那么 ming-chao 要不要全部去掉,还是留下 -chao?
*/
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
struct word
{
const char* data;
size_t length;
};
bool found_inbuf( struct word words[], size_t* words_size, const char* search_data, size_t search_length )
{
for( size_t i=0; i!=*words_size; ++i )
if( words[i].length==search_length && memcmp(words[i].data,search_data,search_length)==0 )
return true;
words[*words_size].data = search_data;
words[*words_size].length = search_length;
++*words_size;
return false;
}
void foo( const char* restrict s, char* restrict d )
{
struct word words[1000];
size_t words_size = 0;
size_t idx_s=0, idx_d=0;
for( ; ; )
{
// 读取 非单词部分
size_t idx_t = 0;
int n = sscanf( s+idx_s, "%*[^A-Za-z]%zn", &idx_t );
if( n == EOF )
break;
// 将 非单词部分 原样照搬到目的字符串中
if( idx_t != 0 )
{
memcpy( d+idx_d, s+idx_s, idx_t );
idx_d += idx_t;
idx_s += idx_t;
}
// 读取 单词部分
idx_t = 0;
n = sscanf( s+idx_s, "%*[A-Za-z]%zn", &idx_t );
if( n == EOF )
break;
// 如果 单词 不重复,则将 单词 照搬到目的字符串中
bool bfound = found_inbuf( words, &words_size, s+idx_s, idx_t );
if( !bfound )
{
memcpy( d+idx_d, s+idx_s, idx_t );
idx_d += idx_t;
}
idx_s += idx_t;
// 这个 单词 有尾巴(比如 Ming's 中的 's)吗?若有,同上处理
for( ; s[idx_s]>' '; ++idx_s )
{
if( !bfound )
d[idx_d++] = s[idx_s];
}
}
d[idx_d] = '\0';
return;
}
int main( void )
{
const char* s = "Xiao Ming's story: Xiao Ming's father walks into the cafe. Someone shouted, \"Xiao Ming, your father is here.\"";
char* d = malloc( strlen(s)+1 );
foo( s, d );
puts( s );
puts( d );
}
输出
Xiao Ming's story: Xiao Ming's father walks into the cafe. Someone shouted, "Xiao Ming, your father is here."
Xiao Ming's story: father walks into the cafe. Someone shouted, " your is here."