我需要在 Qt C++ 中实现方法,该方法在用户键入时计算 QTextEdit 中的字数。此外,当用户键入多个空格时,它们不应被视为单词。我知道如何在已经输入的文本上执行此操作,但我需要一直更新单词总数。你能帮我解决这个问题吗?
5 回答
我建议你连接void QTextEdit::textChanged () [signal]
并使用这样的东西:
void onTextChanged()
{
int wordCount = textEdit->toPlainText().split(QRegExp("(\\s|\\n|\\r)+")
, QString::SkipEmptyParts).count();
}
您几乎必须自己解析它,使用单个拆分器拆分字符串并不是生产的好解决方案。这是我前段时间写的一个简单的解析器,它就是这样做的:
void processChar(const QChar &ch)
{
// if char is not separator
if (!sp[ch.unicode()]){
if (!isWord){ // set where word begins
wordBegin = counter;
isWord = 1;
}
++textChar;
}
// if char is separator
else{
// if there is a current word
if (isWord){
QString tempWord(text.mid(wordBegin, counter - wordBegin));
tempWord = tempWord.toLower();
// if word does not exist add with value one
if (!words.contains(tempWord)){
words.insert(tempWord, 1);
++uniqueWords;
}
// if word exists find its value and increment by one
else {
words.insert(tempWord, words.value(tempWord) + 1);
}
++totalWords;
isWord = 0;
}
// else skip
++sepChar;
}
}
您调用processChar()
文本的每个字符。
它非常快,它使用一个查找表(字符数组)sp
,其中包含所有字符并标记那些是分隔符的。这是从所有分隔符的 QString 填充表格的方法。
void indexChars()
{
// zero everything
for (unsigned i = 0; i < 65536; ++i) sp[i] = 0;
// set every separator index to 1
for (int i = 0; i < separators.length(); ++i) {
sp[separators.at(i).unicode()] = 1;
}
}
该表很大,因为我也希望能够处理 16 位字符。
它有多快 - 尽管做了额外的工作,但它比 MS Word 的字数快 20 倍,而且它实际上创建了一个列表,其中包含文本中每个唯一单词加上出现次数的列表,存储在 QMap 中words
。它跟踪文本字符textChar
、分隔符sepChar
、总单词和唯一单词。
功能可能有点矫枉过正,但如果你不需要所有额外的东西,你可以把它去掉。如果您删除不需要的内容,它会变得更快。
您可以使用这些片段,如果文本自上次计数后发生更改,则可以使用计时器定期计数单词,这是比替代方案更好的解决方案 - 计数文本字段的每个键入的字符。
编辑:
我想我记得很清楚 QTextDocument 是如何工作的(我认为这contentsChange(int position, int charsRemoved, int charsAdded)
是在实际更改之前调用的)。我错了,或者新版本中的行为已经改变。无论如何,对于当前版本(5.0.1),我看不到如何计算对字数的校正。看起来这是不可能的。至少我看不到一种方法来计算删除了多少单词。
听来自QTextDocument :contentsChange(int position, int charsRemoved, int charsAdded)
和的两个信号contentsChanged()
。第一个在文档修改之前触发,第二个在修改之后触发。使用此信息:位置、charsRemoved、charsAdded;计算对总字数的修正。
如果要计算文档从一开始就包含多少个单词,最好的解决方案是:
void MainWindow::docChanged()
{
QTextDocument *doc = qobject_cast<QTextDocument *>(sender());
QRegExp re("\\b\\w+\\b");
int wordCount = 0;
QTextCursor c = doc->find(re);
while (!c.isNull()) {
wordCount++;
c = doc->find(re, c);
}
ui->labelWordCount->setText(QString::number(wordCount));
}
我就是这样做的,我从这个线程上的一些答案中进行了组合。我注意到这个解决方案非常快,如果不需要,它不会浪费资源。它在您键入时仅检查部分文本,只有在您粘贴文本时才会检查整个文本。我希望有人检查此代码并发布一些反馈。这是代码:
size = 0;
counter = 0;
start = 0;
end = 0;
void MainWindow::count()
{
text = ui->textEdit->toPlainText();
if(text.length()-size == 1){
if(text.length() == 1){
if(!text.at(0).isSpace()){
counter++;
ui->label_2->setText(QString::number(counter));
}}
if(text.length()>2){
start = text.length()-1;
end = text.length();
if(text.at(start-1).isSpace() && !text.at(end-1).isSpace()){
counter++;
ui->label_2->setText(QString::number(counter));
}}}
else if(text.length()-size > 1){
counter = 0;
if(!text.at(0).isSpace()) counter++;
for(int i = 1; i<text.length();i++){
if(!text.at(i).isSpace() && text.at(i-1).isSpace())
counter++;
}
ui->label_2->setText(QString::number(counter));
}
size = text.length();
}