【问题标题】:Treat delimiters as input tokens将分隔符视为输入标记
【发布时间】:2013-08-13 07:04:48
【问题描述】:

我想知道如何在 C++ 和 Java 中做到这一点(编辑:我不是说同时。我问了两个类似的问题,“我如何在 C++ 中做到这一点?”和“如何做我用 Java 做这个?”)。

我想解析来自文件的输入并将 '(' 和 ')' 视为除空格之外的分隔符。但我也希望每次遇到 '(' 或 ')' 都被识别为一个单独的标记。所以例如在解析时

this contians(嵌套(括号))

我希望连续调用 next()(或 >>)给(每行一个)

This
contains
(
nested
(
parentheses
)
)
<end of input>

是否有内置此功能的解析器/扫描器?我知道 Java 的 Scanner 很强大,但据我所知,每次遇到下一个标记时,无法确定 哪个 分隔符匹配。

【问题讨论】:

  • 把这个问题分成两个问题会更合适吗?一个用于 C++,一个用于 Java?
  • 您可能想了解compiler compilers。例如,ANTLR 能够为 Java 和 C(当然可以在 C++ 中使用)创建解析器代码。
  • 对不起,我不是同时的意思。我试图将两个类似的问题塞进一个:“我如何在 C++ 中做到这一点?”和“我如何在 Java 中做到这一点?”我会澄清的
  • 如果这是 python,正确的工具是 shlex。它正是这样做的

标签: java c++ parsing delimiter parentheses


【解决方案1】:

Compiler-compiler 讨论不谈,这种解析器可以使用两个索引天真地实现,如下所示:

for(int i = 0; i < str.size(); ) {
  int j = i;
  for(; j < str.size(); ++j) {
    // check for spaces
    if(str[j] == ' ') {
      // capture substring index i to j-1 as a token
      i = j+1;
      break;
    }

    // check for brackets
    if(str[j] == '(' || str[j] == ')') {
      // str[j] is a token
      i = j+1;
      break;
    }

  }

  // no more characters to check
  if(j >= str.size()) break;
}

基本上i是一个标记,表示一个token的开始,j用于搜索token的结束位置。

免责声明:上面的代码未经测试,可能包含语法错误和错误,尤其是空输入、空白等,并且可能在大数据上表现不佳。在重新发明轮子之前,请考虑使用 3rd 方库。

或者对于代码量最少的解决方案,您可以将每次出现的“(”替换为“(”(同样使用“)”)并进行空格标记化:

str.replaceAll("(", " ( ").split("\s+");

【讨论】:

  • 是的,我的问题是询问 STL 中是否存在这样的设备,但我很乐意接受具有相同功能的第 3 方库。我找不到适用于 C++ 或 Java 的,这很奇怪,因为在我看来它是一个相当典型的用例。
  • 如果我从流而不是字符串中提取数据,则 replaceAll 选项不起作用。我想要一些可以一次性完成的事情(我当然可以单独提取单词,然后放回分隔符和后面的所有内容,或者维护一个已经拆分的待读令牌队列,但是这两个选项似乎仍然像解决本应非常简单的问题的大讨厌黑客)
  • 您的代码无法捕获紧跟开/关括号(无空格)的字符串标记。它直接跳到paren。因此,对于我的示例,您的代码将返回“This”、“contains”、“(”、“nested”、“(”、“)”、“)”并遗漏“括号”一词。你介意修理它来处理那个案子吗?在我看来,您需要某种放回方法,或者您需要跟踪当前大小或其他东西。
  • @dspyz 我快速编写代码的目的是为您提供基本的想法,而不是最终的解决方案。所以作为一个“有动力”的程序员,我相信你应该能够自己修复它
  • 我承认这一点,但该修复说明了您的代码的主要问题,即它假定我正在列出结果而不是创建迭代器。 C++ 没有“yield”关键字,所以这并不是我的问题的真正解决方案。
【解决方案2】:

这应该可以通过正则表达式轻松处理。 类似于 `"\\s*(?:(\\w+)|([()]))" 的东西应该做 C++11 中的技巧(对于早期版本的 C++,你需要 提升正则表达式)。 Java也有正则表达式 支持,所以你应该可以在那里做同样的事情。

在这两种情况下,上面的表达式都会跳过空格,然后 “捕获”第 1 组中的符号,或第 2 组中的括号。

【讨论】:

  • 如何处理正则表达式? C++ 是否有某种与实例匹配的扫描器?
  • @dspyz 正则表达式是 Java 和现代 C++ 的一部分。如果你有一个最新的编译器,使用 C++11,你可以使用 std::regexstd::regex_search;否则,您将需要 Boost 正则表达式(并将 std:: 替换为 boost::)。在 Java 中,它位于 java.util.regex
  • 我查找了 std::regex 和 std::regex_search。该解决方案与其他解决方案存在相同的问题。它作用于字符串,而不是流。我正在寻找建立在流或流方法之上的迭代器。重点是从文件或标准输入中逐一读取这些标记,而不是从现有字符串创建元素列表。
  • @dspyz std::regex 不需要字符串。然而,它需要一个双向迭代器,它不包括流。在实践中,几乎任何分词器都会出现这种情况,因为一旦找到结束,它就必须能够从令牌的开头复制到结尾。我自己的 RE 类将使用输入迭代器,但它不执行捕获,并且它对输入迭代器并不是真正有用,除非您设计一个特殊的迭代器,它保留它所看到的内容的副本。在全球范围内,通常最好将输入块读入字符串。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
  • 1970-01-01
  • 2013-10-02
  • 1970-01-01
  • 1970-01-01
  • 2010-12-26
相关资源
最近更新 更多