对WORD文档的关键字搜索

 

在网上找了很久,基本上对OFFICE编程都是用的OFFICE的OLE对象,但是关键字搜索这个问题,感觉用OLE对象显得臃肿,而且不够灵活,于是便写直接读取文件内容进行搜索的办法。

首先涉及的问题就是字符编码的问题。先是在网上稍稍补充了一下关于UNICODE的基础知识,呵呵,不过讲到的东西有点多,GB、UNICODE、UTF……,也没空细细捋顺它们的关系,知道了个大概。最重要的就是了解了如何在VC下用UNICODE,呵呵。主要有:

1.为工程添加UNICODE和_UNICODE预处理选项,在VC.net中就是 项目 -> 属性 -> c/c++ -> 预处理器 在“预处理定义”中加入这两个宏定义(vc6中 project -> settings -> c/c++ -> general 中的 Preprocessor definitions)。

2.Include <TCHAR.h>(一般在stdafx.h中)然后把所有使用char*定义变量的地方换为LPTSTR/TCHAR*或LPCTSTR/const TCHAR*(对应于const char*)。

3.把所有的字符串常量用_T()宏包起来,比如 TCHAR* szText = _T("我的Text")。

至于说把所有的C库字符串操作函数也做相应的替换,在这里我倒是没用上多少。

下面说说我的程序。

首先,通过用ultraedit对几个word文档的实验观察,发现它是这样的:WORD中如果内容都是英文的,则用ASCII码存储,一旦出现汉字,则都用unicode存储。

一开始所以我在扫描文件的时候,同时用两个缓冲区保存两种编码方式读到的内容,一个是WORD型的(wUBuffer),一个是TCHAR型的(cABuffer[2]),(这里为了叙述方便,假定了缓冲区的大小)然后两个都与待查内容比较。

这里算法是这样的:

1、读入一个WORD(两个字节,低位在前,高位在后)到wUBuffer。

2、将读到的两个字节的低位赋给cABuffer[1]。

3、wUBuffer的高位若为0,则不处理;高位若不为0,将cABuffer左移一个元素,即aABuffer[0]=aABuffer[1],然后将wUBuffer的高位赋给aABuffer[1]。

实际上当然不会只用这么小的缓冲区。这两个缓冲区的开辟是根据待查字符串的长度。

后来忽然想到,按照上面的方法对文件一路读下去,是两个字节两个字节的读,并未实现真正的逐字节扫描,于是做了如下改进:

对WORD型和TCHAR型分别开辟两个缓冲区wUBuffer[0]、wUBuffer[1]、aABuffer[0]、aABuffer[1],下标为0的记录扫描第偶数个字节时的内容,下标为1的记录第奇数个字节时的内容,这样在用i做循环对文件扫描时,只要wUBuffer[i % 2]和aABuffer[i % 2]就行了。而这四个缓冲区又分别是记录读取内容的数组,即实际上都是二维数组。在用i做文件字节数的循环时,每次循环都把文件指针指向偏移i的位置即可。

下面是代码。算法都实现在这了,应用时可根据实际需要改进。比如这里是找到即停止,实际上可以继续查找,把所有找到的地方都记录下来,最后一起显示,也可以做成像搜索引擎那样把找到的关键字前后的一些内容一块显示出来。

int  SearchInDoc()
{
    CString strToFind
=_T("牧场");
            
    DWORD l
=strToFind.GetLength();
            
    
//开辟缓冲区。unicode和ASNI各用两个,[0]用于扫描偶数字节时的,[1]用于扫描奇数字节时
    WORD* wUBuffer[2];
    wUBuffer[
0]=new WORD[l+1];    //unicode 编码时的查找缓冲区
    wUBuffer[1]=new WORD[l+1];    //unicode 编码时的查找缓冲区
    LPTSTR cABuffer[2];
    cABuffer[
0]=new TCHAR[l+1];    //与wUBuffer等长的ANSI编码时的查找缓冲区
    cABuffer[1]=new TCHAR[l+1];    //与wUBuffer等长的ANSI编码时的查找缓冲区
    CString strUBuffer[2],strABuffer[2]; //字符串缓冲区,便于操作
    DWORD i,j;
    
    
//初始化4个缓冲区
    for(i=0;i<l;i++)    
    
{
        wUBuffer[
0][i]=0xffff;
        cABuffer[
0][i]=(TCHAR)0xff;
        wUBuffer[
1][i]=0xffff;
        cABuffer[
1][i]=(TCHAR)0xff;
    }

    
//最后一个元素保存字符串结束符(实际上是赋值为结束符,但是这里好像会被当成实际的结束符,导致后面的代码消失,故用0暂时代替)
    wUBuffer[0][l]=0;
    cABuffer[
0][l]=0;
    wUBuffer[
1][l]=0;
    cABuffer[
1][l]=0;

    HANDLE hFile;
    hFile 
= CreateFile(_T("f:/玩在北京.doc"), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
        
    
if(hFile == INVALID_HANDLE_VALUE){
        
//TRACE("read error:%s %d ", pFilePath, GetLastError());
        return 0;
    }


    DWORD dwReadLen,dwFileLen
=GetFileSize(hFile,NULL);
    
    
for(i=0;i<dwFileLen;i++)    //扫描文件
    {
        SetFilePointer(hFile, i, NULL, FILE_BEGIN);  
//设置文件指针位置

        
//两个缓冲区都左移一个元素
        for(j=0;j<l-1;j++)    
        
{
            wUBuffer[i 
% 2][j]=wUBuffer[i % 2][j+1];
            cABuffer[i 
% 2][j]=cABuffer[i % 2][j+1];
        }

            
        
//向Unicode缓冲区最后一个元素读入两个字节
        ReadFile(hFile, &wUBuffer[i % 2][l-1], 2&dwReadLen, NULL);
        
//将读到的两个字节处理:
        
//将低位赋给cABuffer[l-1]
        
//高位若为0,则不处理;
        
//高位若不为0,将cABuffer再左移一个元素,赋给cABuffer[l-1]
        
        cABuffer[i 
% 2][l-1]=(wUBuffer[i % 2][l-1& 0x00ff);
        
if((wUBuffer[i % 2][l-1& 0xff00)>0x0000)
        
{
            
for(j=0;j<l-1;j++)    
                cABuffer[i 
% 2][j]=cABuffer[i % 2][j+1];
            cABuffer[i 
% 2][l-1]=((wUBuffer[i % 2][l-1& 0xff00)>>8);
        }


        
        strUBuffer[i 
% 2]=(CString)wUBuffer[i % 2];
        strABuffer[i 
% 2]=(CString)cABuffer[i % 2];
        strToFind.AnsiToOem();
        strUBuffer[i 
% 2].AnsiToOem();
        strABuffer[i 
% 2].AnsiToOem();

        
if(strUBuffer[i % 2]!="" && (strUBuffer[i % 2].Find(strToFind)>-1))
        
{
            cout
<<"Found!"<<endl;
            cout
<<"Unicode"<<endl;

            delete []wUBuffer[
0];
            delete []wUBuffer[
1];
            delete []cABuffer[
0];
            delete []cABuffer[
1];
            
return i-l;
        }

        
if(strABuffer[i % 2]!="" && (strABuffer[i % 2].Find(strToFind)>-1))
        
{
            cout
<<"Found!"<<endl;
            cout
<<"ANCI"<<endl;

            delete []wUBuffer[
0];
            delete []wUBuffer[
1];
            delete []cABuffer[
0];
            delete []cABuffer[
1];
            
return i-l;
        }

    }


    delete []wUBuffer[
0];
    delete []wUBuffer[
1];
    delete []cABuffer[
0];
    delete []cABuffer[
1];
    cout
<<"Not Found!"<<endl;

    CloseHandle(hFile);

    
return -1;
}
调试过程中还出了个插曲,VC莫名其妙不认识UNICODE预编译了,调用AnsiToOem()的时候硬是说'CharToOemA' : is not a member of 'CString' ,后来又莫名其妙好了,真是FT,耗了一天的时间。详见 http://community.csdn.net/Expert/topic/5410/5410681.xml?temp=.88081,呵呵。
在Excel查找Word文档关键字有多种方法。以下介绍一些简便的方法。 方法一:使用快捷键“Ctrl + F” 在Excel,使用“Ctrl + F”快捷键打开查找和替换对话框。在“查找”输入要查找的关键字,然后点击“查找下一个”按钮。如果输入的关键字存在于Word文档,Excel就会自动定位到该关键字所在的位置。 方法二:使用Excel“数据”选项卡下的“从文本”功能 在Excel,选择“数据”选项卡下的“从文本”功能,然后选择要查找的Word文档。在“文本导入向导”的第三个步骤,可以选择“分隔符”或“文本限定符”来确定如何按行将文本拆分成单元格。如果要查找的文本是在一行,可以使用“其他”的分隔符选项,并在文本框输入适当的分隔符(如“|”或“,”等)。完成配置后,单击“完成”按钮即可。 方法三:使用Excel“外部数据”选项卡下的“从其他源”功能 在Excel,选择“外部数据”选项卡下的“从其他源”功能,然后选择要查找的Word文档。选择“Microsoft Word”选项,并按需配置数据源。然后单击“确定”按钮,即可打开“导入数据”向导,以将Word文档作为数据源导入到Excel。在导入数据后,可以使用Excel的过滤功能或排序功能来查找指定的文本。 总的来说,以上方法都可以快捷地在Excel查找Word文档关键字。但需要注意的是,在第一种方法,只能查找一个关键字;在第二种方法和第三种方法,可以根据需要查找多个关键字
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值