【问题标题】:Finding word patterns in a dictionary, high performance在字典中查找单词模式,高性能
【发布时间】:2012-12-05 13:47:27
【问题描述】:

我需要构建某种字典,其中还包含每个单词在该语言中出现的词频。通常,这将使用 std::unordered_map 来实现,对吗?现在问题来了……我想找到所有符合某个正则表达式的单词及其频率,而性能是我最关心的问题。

我认为我无法避免迭代一系列元素并逐元素检查它们是否与模式匹配。因此,我认为使用一对向量而不是地图可能更聪明:

using namespace std;
typedef vector<pair<string, double>> Dictionary
vector<Dictionary::const_iterator> index;
Dictionary dict;
...
for_each(index['d'], index['e'], DoSomething);

这将允许我有效地迭代所有以“d”开头的单词。当然,这只有在我已经知道我的正则表达式的第一个字母时才有帮助,而我认为这通常不是这种情况。此外,如果我已经毫无疑问地知道整个单词并且只想查找它的频率,我将不得不遍历整个部分,直到找到它。地图可以让我更快地查找它。例如。在寻找“鹿”这个词时

Dictionary::const_iterator it = 
    find_if(index['d'], index['e'], []    // Lambda
        (pair<string, double> const &pr)
        {
           return pr.first == "deer";
        });

根本不是最优的!一个解决方案可能是针对不同情况使用不同的字典实现,尽管内存不是大问题,但这似乎是一个愚蠢的解决方法。

有什么建议吗?

【问题讨论】:

    标签: c++ regex dictionary map unordered-map


    【解决方案1】:

    按照您的想法,一个 std::vector&lt;std::pair&lt;boost::regex, int&gt; &gt; 可能是 最有效的;您反复尝试寻找匹配项。

    一个更好的解决方案,如果你愿意做这项工作,会 是实现你自己的正则表达式类,没有 捕获(大多数正则表达式中的 (...) 运算符)。 没有捕获,转换正则相当容易 表达式为纯 DFA, 可以是 正则 表达式,每个正则表达式返回不同的 接受代码。 (这是我自己的正则表达式类的方式 作品。对于大多数应用程序来说,它的灵活性不如 Boost,因为它不支持捕获。但它确实 允许这样的事情:

    RegularExpression t1( expr1", 0 );
    RegularExpression t2( expr2", 1 );
    //  ...
    RegularExpression t = t1 | t2 /* | t3 | t4 | ... */ ;
    

    匹配时,expr1匹配返回0,expr2匹配返回1 比赛等;然后,您可以使用匹配 id 作为索引 一个整数向量。 (如果没有匹配则返回 -1。)

    这样做,搜索时间与 输入的长度。不管表达多少 你正在尝试匹配。 (我的正则表达式类是 20 多年前设计的,用于生成编译器 前端。大约 15 年前,我重做了它来处理 UTF-8 输入。)

    多年来,代码都在网络上提供,但我没有 目前有一个网页,所以除非有人保留了旧的 复制,不是。我很乐意把它寄给你,但是 警告图书馆有一段时间没有维护了,所以 让它与现代编译器一起编译可能并非易事 编译器。 (它最初是用准标准 C++ 编写的,并且 仍然包含许多变通方法以使其编译 与 Sun CC 4.x 之类的东西。)

    【讨论】:

    • 哇,信息量很大!很好的信息虽然......真的很感激!我认为编写 DFA 应该是相当可行的,但如果您不介意我要求一些额外的解释:您提到的 vector&lt;int&gt; 的目的是什么(由匹配 ID 索引)?此外,vector&lt;pair&lt;RegularExpression, int&gt;&gt; 如何适应?我的频率信息(双精度)现在存储在哪里?对不起,如果这些都是琐碎的,我是这个专业领域的新手。
    • @user1428839 vector&lt;int&gt; 只是为了收集计数;所有RegularExpression(至少在我的实现中)都会返回一个int:如果不匹配,则返回-1,否则返回其构造函数的第二个参数。这是一个vector&lt;pair&lt;boost::regex, int&gt; &gt;;使用广泛可用的正则表达式类的替代方法。至于其余的,解析正则表达式以构建 DFA 是一项大量工作。我这样做是因为我当时需要它。 (另一方面,我的代码可以使用 InputIterator,而且它很快。)
    • @jamer-kanze 嗯,好吧。我只需要解析根本不需要通用的非常简单的表达式,所以在我的情况下它可能会减少工作,但我明白你的意思。谢谢!
    • @user1428839 对于非常简单、固定的表达式,我手动计算了 DFA。我以为你会得到模式作为用户输入或其他东西。
    • 实际上,我需要为解密的部分解分配一个值,以估计继续解密过程的有用性。如果部分解决方案是“T.ecows.ysm.o”(Thecowsaysmoo),它应该继续运行,而“Hna.sadd.cc.a”不会产生任何结果。因此,我需要将这些字符串的片段与字典进行匹配,但这些片段主要是缺少一些字母的单词。
    【解决方案2】:

    您最好的选择是使用像http://www.ims.uni-stuttgart.de/projekte/gramotron/SOFTWARE/SFST.html 这样的有限Satae 传感器。

    正如你所说,地图会占用很多空间。

    您可以将转换器视为一个大的正则表达式(正则表达式是一个编译的自动机)。

    【讨论】:

    • 一个大的正则表达式是解决方案:您可以使用boost::regex m( "(" + expr1 + ")|(" + expr2 + ")... ) 之类的东西,但您仍然必须迭代子匹配,以确定哪个匹配。虽然真正的正则表达式编译为 DFA,但一旦添加了捕获,我认为它不会;我熟悉的所有实现都使用 NFA,并且大多数使用回溯,这意味着复杂性受到匹配表达式的复杂性的影响。
    猜你喜欢
    • 1970-01-01
    • 2011-02-07
    • 1970-01-01
    • 1970-01-01
    • 2021-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-05
    相关资源
    最近更新 更多