【问题标题】:For Java, there is a tokenizator that is matches exactly what I want?对于 Java,有一个标记器与我想要的完全匹配?
【发布时间】:2011-07-28 18:24:26
【问题描述】:

我想标记文本,但不只用空格分隔。

有些东西,比如专有名称,我只想设置一个标记(例如:“Renato Dinhani Conceição”)。另一种情况:percentual ("60 %") 并且没有分成两个标记。

我想知道是否有某个库中的 Tokenizator 可以提供高度自定义?如果没有,我会尝试自己写,如果有一些接口或实践可以遵循。

并非所有事情都需要得到普遍认可。示例:我不需要重新识别中文字母。

我的申请是大学申请,主要针对葡萄牙语。只有名称、地点和类似名称等某些内容来自其他语言。

【问题讨论】:

  • 如果您设法以简单的程序化方式解决了这个问题,我很确定您将获得 ACM 图灵奖。
  • 确实,这似乎是在尝试使用静态算法做一些事情,这确实需要某种知识库和人工智能。实际上,您已经可以看到这不会发生,因为没有解决未决问题的算法。
  • 专有名称检测,又称命名实体识别,是一个活跃的研究领域。这不是标记化,这是成熟的 NLP。
  • 要了解更多关于 NLP/信息提取的信息,请查看这篇文章 - stackoverflow.com/questions/573620/… 并尝试 NLP 中现有的方法 - 我建议使用 nltk 工具包并阅读相应的书 (可用。在 nltk 页面上)--nltk.org.

标签: java text nlp tokenize


【解决方案1】:

我不会尝试从标记化的角度,而是从规则的角度来解决它。这将是最大的挑战 - 创建一个能够满足大多数情况的综合规则集。

  • 用人类术语定义不应基于空格分割的单元。名称示例是一个。
  • 对于空格拆分的每个例外,创建一组规则来识别它。对于名称示例:2 个或多个连续的大写单词,中间有或没有特定于语言的非大写名字单词(如“de”)。
  • 将每个规则实现为自己的类,可以在循环时调用。
  • 根据空格拆分整个字符串,然后循环它,跟踪之前出现的标记和当前标记,为每个标记应用您的规则类。

规则 isName 的示例:

  • 循环 1:(eg.: isName = false
  • 循环 2:"Renato isName = true
  • 循环 3:Dinhani isName = true
  • 循环 4:Conceição"). isName = true
  • 循环 5:Another isName = false

留下:(eg.:"Renato Dinhani Conceição").Another

【讨论】:

  • 我喜欢这个主意。关于它的两个问题:在任何库中都实现了一些 isSomething() 吗?使用正则表达式进行验证还是按字符运行字符串字符更好?
  • 一直在找,还没找到。另请注意,即使存在 lib,您可能仍需要(可能需要)实现自己的规则。
  • 他可以先使用命名实体识别器,然后将每个识别的实体视为一个标记,将所有不是实体的东西视为单独的标记。这摆脱了规则,自动识别专有名词,剩下的就是一个正则表达式。
  • 好电话 - 我没想到 NLP。这是 NER 上的 Stack Overflow 页面:stackoverflow.com/questions/188176/…。 OpenCalais 是选定的选项。不错!
【解决方案2】:

我认为分词器对于您想要的东西来说太简单了。比标记器更进一步的是像 JFlex 这样的词法分析器。这些会将字符流拆分为单独的标记,例如标记器,但规则更灵活。

即便如此,您似乎仍需要某种自然语言处理,因为教词法分析器区分专有名称和普通单词可能会很棘手。通过教它以大写字母开头的一串单词都属于同一类,数字后面可能跟单位等,你可能会走得更远。祝你好运。

【讨论】:

    【解决方案3】:

    你应该试试Apache OpenNLP。它包括现成的葡萄牙语句子检测器和标记器模型。

    下载 Apache OpenNLP 并解压。将葡萄牙语模型复制到 OpenNLP 文件夹。从http://opennlp.sourceforge.net/models-1.5/下载模型

    从命令行使用它:

    bin/opennlp TokenizerME pt-ten.bin 
    Loading Tokenizer model ... done (0,156s)
    O José da Silva chegou, está na sua sala.
    O José da Silva chegou , está na sua sala .
    

    使用 API:

    // load the model
    InputStream modelIn = new FileInputStream("pt-token.bin");
    
    try {
      TokenizerModel model = new TokenizerModel(modelIn);
    }
    catch (IOException e) {
      e.printStackTrace();
    }
    finally {
      if (modelIn != null) {
        try {
          modelIn.close();
        }
        catch (IOException e) {
        }
      }
    }
    
    // load the tokenizer
    Tokenizer tokenizer = new TokenizerME(model);
    
    // tokenize your sentence
    String tokens[] = tokenizer.tokenize("O José da Silva chegou, está na sua sala.");
    

    【讨论】:

      【解决方案4】:

      StringTokenizer 是一个遗留类,仅为了向后兼容而维护。在新代码中不鼓励使用它。

      您应该使用 String.split() 函数。 split 函数将正则表达式作为参数。此外,您可以使用 Pattern 和 Matcher 类来增强它。您可以编译您的模式对象,然后使用它来匹配各种场景。

      【讨论】:

      • 人名不规则,因此无法使用此方法将全名识别为令牌。名称是原始问题中确定的特定用例。
      • 我怀疑这个问题的发布者是在要求一种通用的方法来拆分他的所有字符串。在这种情况下,他的要求听起来更像是最佳实践。
      • 可能是这样。我将这个问题解释为寻找一些用于字符串处理的超级框架。我想这取决于您如何阅读问题。
      • 我发布的两个示例是我在第一次测试中看到的第一件事,但可能会出现新情况。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-03
      • 2015-07-02
      • 2020-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多