5

我需要在 Qt C++ 中实现方法,该方法在用户键入时计算 QTextEdit 中的字数。此外,当用户键入多个空格时,它们不应被视为单词。我知道如何在已经输入的文本上执行此操作,但我需要一直更新单词总数。你能帮我解决这个问题吗?

4

5 回答 5

1

我建议你连接void QTextEdit::textChanged () [signal]并使用这样的东西:

void onTextChanged()
{
    int wordCount = textEdit->toPlainText().split(QRegExp("(\\s|\\n|\\r)+")
                                                  , QString::SkipEmptyParts).count();
}
于 2013-04-06T16:39:11.710 回答
0

您几乎必须自己解析它,使用单个拆分器拆分字符串并不是生产的好解决方案。这是我前段时间写的一个简单的解析器,它就是这样做的:

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、总单词和唯一单词。

功能可能有点矫枉过正,但如果你不需要所有额外的东西,你可以把它去掉。如果您删除不需要的内容,它会变得更快。

您可以使用这些片段,如果文本自上次计数后发生更改,则可以使用计时器定期计数单词,这是比替代方案更好的解决方案 - 计数文本字段的每个键入的字符。

于 2013-04-06T13:40:42.413 回答
0

编辑:
我想我记得很清楚 QTextDocument 是如何工作的(我认为这contentsChange(int position, int charsRemoved, int charsAdded)是在实际更改之前调用的)。我错了,或者新版本中的行为已经改变。无论如何,对于当前版本(5.0.1),我看不到如何计算对字数的校正。看起来这是不可能的。至少我看不到一种方法来计算删除了多少单词。

听来自QTextDocument :contentsChange(int position, int charsRemoved, int charsAdded)和的两个信号contentsChanged()。第一个在文档修改之前触发,第二个在修改之后触发。使用此信息:位置、charsRemoved、charsAdded;计算对总字数的修正。

于 2013-04-06T14:28:30.983 回答
0

如果要计算文档从一开始就包含多少个单词,最好的解决方案是:

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));
}
于 2013-04-06T17:41:51.690 回答
0

我就是这样做的,我从这个线程上的一些答案中进行了组合。我注意到这个解决方案非常快,如果不需要,它不会浪费资源。它在您键入时仅检查部分文本,只有在您粘贴文本时才会检查整个文本。我希望有人检查此代码并发布一些反馈。这是代码:

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();
}
于 2013-04-06T21:32:50.817 回答