通过QT查找Word中的关键字,并做高亮或删除操作
最近由于项目需要,要用qt操作word文档。具体的工作需求:在指定的word文档(*.doc文件/*.docx文件)中查找关键字,找到后做高亮操作或者直接删除操作,然后另存为到别的目录(表示这个文件被操作过了)。
这个功能很简单,确实挺简单,但由于是第一次用qt操作word文档,所以仍需要经过一番查找资料。网上用qt操作word文档的资料不是很多(可能是我没找对地方),所以经过了一段时间的碰壁之后(没有现成的,哪怕是半成品),我决定还是从源头看起:
1.查看帮助文档:microsoft word visual basic参考.chm。这是操作word文档的vba接口文档
2.查看官方网站的帮助文档:https://docs.microsoft.com/en-us/dotnet/api/microsoft.office.interop.word?view=word-pia
“查找”在这:https://docs.microsoft.com/en-us/dotnet/api/microsoft.office.interop.word.find.hithighlight?view=word-pia#microsoft_office_interop_word_find_hithighlight_system_object__system_object__system_object__system_object__system_object__system_object__system_object__system_object__system_object__system_object__system_object__system_object__system_object__system_object__system_object__system_object__system_object__system_object__system_object__system_object__
要想用qt操作office文档,就要用到qaxwidget类和qaxobject类首先要在pro文件中配置一个模块“qaxcontainer”,也就是添加一行代码,即:
config += qaxcontainer
在找到关键字之后,我还保存了一些数据:文件名、文件所在的路径、关键字所处的位置。如果你不需要这些数据,可以删减掉。
qlist<qstring> filenamelist; // 保存文件名
qlist<qstring> filepathlist; // 保存文件路径
qlist<qstringlist> keywordspositionlist; // 保存关键字所在位置
首先介绍一个函数,这个函数通过正则表达式用来定位关键字所处在的语句。这个函数会在后面的高亮操作函数和直接删除函数里调用到:
// 查找关键字的位置 // filecontent:文件内容;keyword:关键字 qstringlist findkeywordsposition(qstring filecontent, qstring keyword) { qstringlist reslist; if (filecontent.contains(keyword)){ qdebug() << qobject::tr("包含子字符串 : %1").arg(keyword); int startindex = 0; // int count = 0; int keywordslen = keyword.length(); qregexp rx(qobject::tr("[,。:\r]?([^,。:\r]*(%1)[^,。:\r]*)[,。:\r]?").arg(keyword)); while ((startindex = rx.indexin(filecontent, startindex)) != -1){ qstring resstr = rx.cap(1).mid(0); // 提取子字符串所在的语句 if (resstr.contains("\r")) resstr.replace("\r", ""); reslist << resstr; // 找到子字符串 int findindex = filecontent.indexof(keyword, startindex); // qdebug() << qobject::tr("keywords 出现的位置 : %1").arg(findindex); startindex = findindex + keywordslen; // qdebug() << qobject::tr("keywords 出现的次数 : %1").arg(++count); qdebug() << "\n"; } return reslist; } return reslist << ""; }
首先是高亮操作函数:
// 高亮操作函数
// dirname:是待检查文件的路径;keywords:是要查找的关键字(查找的关键字可能是多个) bool highlightkeywordsinwordfile(qstring dirname, qstringlist keywords) { int lastseparatorindex = dirname.lastindexof(qdir::separator()); qstring saveasfilepath = storedir + dirname.mid(lastseparatorindex+1); // 另存为的路径 qaxwidget wordapplication("word.application"); qaxobject *documents = wordapplication.querysubobject("documents"); documents->dynamiccall("open(const qstring&)", dirname); wordapplication.setproperty("visible", qvariant(false)); qaxobject* m_doc = wordapplication.querysubobject("activedocument"); // 获取当前工作簿 qaxobject* prange = m_doc->querysubobject("content()"); if (null != prange) { // 查找关键字 qaxobject *pfind = prange->querysubobject("find()"); qstringlist keywordsposition; if (null != pfind) { pfind->dynamiccall("clearformatting()"); pfind->setproperty("format", true); pfind->setproperty("matchcase", false); pfind->setproperty("matchwholeword", false); pfind->setproperty("matchbyte", true); pfind->setproperty("matchwildcards", false); pfind->setproperty("matchsoundslike", false); pfind->setproperty("matchallwordforms", false); for (int i=0; i<keywords.size(); ++i){ // 找到关键字所在的位置,得到一个position,将position添加到keywordsposition中。 qstring keyword = keywords.at(i); qstringlist position = findkeywordsposition(prange->property("text").tostring(), keyword); if (!position.contains("")){ keywordsposition << position; pfind->setproperty("text", keyword); pfind->dynamiccall("execute()"); while (pfind->property("found").tobool()) { bool ishighlight = pfind->parent()->setproperty("highlightcolorindex","wdyellow"); pfind->dynamiccall("execute()"); if (!ishighlight) { delete pfind; pfind = null; delete prange; prange = null; m_doc->dynamiccall("close(boolean)", true); wordapplication.dynamiccall("quit ()"); delete m_doc; m_doc = null; return false; } } } } } if (keywordsposition.size() >= 1){ qstring filename = dirname.mid(lastseparatorindex+1); qstring filepath = dirname.mid(0, lastseparatorindex+1); filenamelist << filename; filepathlist << filepath; keywordspositionlist << keywordsposition; m_doc->dynamiccall("saveas(const qstring)", saveasfilepath); } delete pfind; pfind = null; delete prange; prange = null; m_doc->dynamiccall("close(boolean)", true); m_doc->dynamiccall("quit()"); delete m_doc; m_doc = null; return true; } return true; }
下面这个是直接删除操作函数
// dirname:是待检查文件的路径;keywords:是要查找的关键字(查找的关键字可能是多个) bool directdeletekeywordsinwordfile(qstring dirname, qstringlist keywords) { int lastseparatorindex = dirname.lastindexof(qdir::separator()); qstring saveasfilepath = storedir + dirname.mid(lastseparatorindex+1); // 另存为的路径 qaxwidget wordapplication("word.application"); qaxobject *documents = wordapplication.querysubobject("documents"); documents->dynamiccall("open(const qstring&)", dirname); wordapplication.setproperty("visible", qvariant(false)); qaxobject* m_doc = wordapplication.querysubobject("activedocument"); // 获取当前工作簿 qaxobject* prange = m_doc->querysubobject("content()"); qlist<qvariant> vars; if (null != prange) { // 查找关键字 qaxobject *pfind = prange->querysubobject("find()"); qstringlist keywordsposition; if (null != pfind) { pfind->dynamiccall("clearformatting()"); qaxobject *replacement = pfind->querysubobject("replacement()"); replacement->dynamiccall("clearformatting()"); for (int i=0; i<keywords.size(); ++i){ qstring keyword = keywords.at(i); // 找到关键字所在的位置,得到一个position,将position添加到keywordsposition中。 qstringlist position = findkeywordsposition(prange->property("text").tostring(), keyword); if (!position.contains("")){ keywordsposition << position; vars << keyword << false << false << false << false << false << true << 1<< false << "" << 2 << false << false << false << false; // wdreplacenone-->0;wdreplaceall-->2;wdreplaceone-->1 bool isreplaced = pfind->dynamiccall("execute(findtext, matchcase, matchwholeword, matchwildcards, matchsoundslike, " "matchallwordforms, forward, wrap, format, replacewith, " "replace, matchkashida, matchdiacritics, matchalefhamza, matchcontrol)", vars).tobool(); if (!isreplaced){ delete pfind; pfind = null; delete prange; prange = null; m_doc->dynamiccall("close(boolean)", true); m_doc->dynamiccall("quit()"); delete m_doc; m_doc = null; qmessagebox openfileerror(qmessagebox::warning, qobject::tr("文件处理错误"), qobject::tr("文件 %1 处理错误,是否继续检查其他文件?").arg(dirname)); openfileerror.addbutton(qmessagebox::yes); openfileerror.addbutton(qmessagebox::no); openfileerror.setdefaultbutton(qmessagebox::yes); if (openfileerror.exec() == qmessagebox::no) return false; } } } } if (keywordsposition.size() >= 1){ qstring filename = dirname.mid(lastseparatorindex+1); qstring filepath = dirname.mid(0, lastseparatorindex+1); filenamelist << filename; filepathlist << filepath; keywordspositionlist << keywordsposition; m_doc->dynamiccall("saveas(const qstring)", saveasfilepath); } delete pfind; pfind = null; delete prange; prange = null; m_doc->dynamiccall("close(boolean)", true); m_doc->dynamiccall("quit()"); delete m_doc; m_doc = null; return true; } return false; }
好了,以上代码可能无法正常运行,因为缺少一些变量的定义、头文件的包含,我觉得这些你自己添加是完全ok的^-^。
因为自己需要的时候找不到资源,如果你也在找相似的资料,能给你带来帮助,我的目的就达到了,哈哈
我发现在网上下载word vba和excel vba帮助文档的时候需要金币什么的,很不方便。在此我还将word vba和excel vba帮助文档的百度网盘下载链接放在这里,供大家下载:
链接: https://pan.baidu.com/s/1-ktgdevz_4c3yp_sbnlkiw 提取码: ri4p
有不足的地方,请指正。