【问题标题】:Splitting text into a list of words with ICU使用 ICU 将文本拆分为单词列表
【发布时间】:2016-08-08 08:18:25
【问题描述】:

我正在开发文本标记器。 ICU 是极少数具有此功能的 C++ 库之一,而且可能是维护得最好的库之一,所以我想使用它。 我找到了关于BreakIterator 的文档,但它有一个问题:我该如何去掉标点符号?

#include "unicode/brkiter.h"

#include <QFile>

#include <vector>

std::vector<QString> listWordBoundaries(const UnicodeString& s)
{
    UErrorCode status = U_ZERO_ERROR;
    BreakIterator* bi = BreakIterator::createWordInstance(Locale::getUS(), status);

    std::vector<QString> words;

    bi->setText(s);
    for (int32_t p = bi->first(), prevBoundary = 0; p != BreakIterator::DONE; prevBoundary = p, p = bi->next())
    {
        const auto word = s.tempSubStringBetween(prevBoundary, p);
        char buffer [16384];
        word.toUTF8(CheckedArrayByteSink(buffer, 16384));
        words.emplace_back(QString::fromUtf8(buffer));
    }

    delete bi;

    return words;
}

int main(int /*argc*/, char * /*argv*/ [])
{
    QFile f("E:\\words.TXT");
    f.open(QFile::ReadOnly);

    QFile result("E:\\words.TXT");
    result.open(QFile::WriteOnly);

    const QByteArray strData = f.readAll();
    for (const QString& word: listWordBoundaries(UnicodeString::fromUTF8(StringPiece(strData.data(), strData.size()))))
    {
        result.write(word.toUtf8());
        result.write("\n");
    }

    return 0;
}

自然地,生成的文件如下所示:

“
Come

outside
.

Best

if

we

do

not

wake

him
.
”

我需要的是只是这些词。如何做到这一点?

【问题讨论】:

  • ispunct 函数呢?您可以检查令牌是否由一个字符组成,然后将其作为整数并使用该函数进行检查。
  • @BiagioFesta:首先,我这里有很多非 ASCII 字符(比如引号)。其次,非单词不一定是单字符(例如逗号 + 空格 + 开头引号)。

标签: c++ utf-8 icu


【解决方案1】:

QT 库包含几个有用的方法来检查 char 的属性: QChar.

确实,您可以从 缓冲区 创建 QString 变量 并检查插入输出向量之前需要的所有属性。

例如:

auto token = QString::fromUtf8(buffer);
if (token.length() > 0 && token.data()[0].isPunct() == false) {
  words.push_back(std::move(token));
}

使用该代码,我可以访问字符串的第一个字符并检查 不管是不是标点符号。

更强大的东西,我将其表示为函数:

bool isInBlackList(const QString& str) {
  const auto len = str.lenght();
  if (len == 0) return true;
  for(int i = 0; i < len; ++i) {
    const auto&& c = str.data()[i];
    if (c.isPunct() == true || c.isSpace() == true) {
      return true;
    }
  }
  return false;
}

如果该函数返回 true,则该标记尚未插入向量中。

【讨论】:

  • 这根本不是一个坏主意。虽然我在这里只是为了方便而使用 Qt,并且希望最终的解决方案只依赖 ICU 和 stdlib。换句话说,我可以只使用 ICU 来检查一个字符的标点符号吗?
  • ICU 没有这种类型的任何方法。目前我正在考虑 REGEX:Regex Class ICU。您可以重新实现函数 isInBlackList 只需检查字符串中的标点符号。如果您需要,请告诉我,我将编辑答案添加这种解决方案!
  • 谢谢。我现在不想给您带来麻烦,也许很快就会有更好的解决方案。而且我对正则表达式也有性能保留。宁愿将黑名单实现为 ​​Unicode 代码点的std::set,但我不想手动填写此列表 - 有很多非文本 Unicode 字符,我不可能全部指定。
猜你喜欢
  • 2021-10-16
  • 1970-01-01
  • 2010-10-21
  • 1970-01-01
  • 2018-03-13
  • 1970-01-01
  • 2010-10-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多