【问题标题】:Regex on InputStreamInputStream 上的正则表达式
【发布时间】:2015-10-26 22:45:55
【问题描述】:

我正在解析来自第 3 方硬件的流的输入。这东西打印出对人类有用的信息。它包括关键字和其他我不关心的字符。我想获取一个流并使用正则表达式找到这些关键字之一的下一次出现。然后我可以做一个switch 语句并找出发送了什么命令。

我不能使用Scanner 类,因为读取被阻塞,我不能中断它来停止线程。我也无法关闭流作为解决方法。

有什么库可以用来做我想做的事情吗?我找到了Streamflyer,但这似乎有点矫枉过正,也许不是我想要的。它还建议了FilterInputStreamFilterReader,但我认为这些不是我想要的。

【问题讨论】:

  • 我会用 Scanner 包装 InputStream,并使用 findWithinHorizo​​n(myPattern, 0) 或 next(myPattern)。对于这两种方法,myPattern 的编写方式会稍有不同,因为第二种方法假定模式从当前位置开始。
  • 如果它“打印出针对人类的消息”,那么它可能会将它们打印为单独的行,因此使用BufferedReader 并调用readLine(),然后在行上运行正则表达式。
  • @YangYing findWithinHorizion 方法会阻塞,如果没有找到,据我所知,您不能中断该阻塞。我错了吗?
  • @Andreas 它有点像在自己的行上打印东西,有一个命令在发送时不会打印新行。

标签: java regex stream inputstream


【解决方案1】:

我有一个开源项目可以帮助解决这个问题,它比基于正则表达式的解决方案快得多:

http://mtimmerm.github.io/dfalex/

大纲:

  • 使用 DfaBuilder 为每个关键字创建一个匹配 .*KEYWORD 的 DFA。指定该模式的最简单方法是Pattern.maybeRepeat(CharRange.ALL).then("KEYWORD");

  • 调用 build(),你会得到一个 DfaState。依次为您输入的每个字符调用state=state.getNextState(c),每当您处于关键字的末尾时,state.getMatch() 都会告诉您匹配到了哪个关键字。

编辑: 建筑是这样的:

//The <Integer> here means you want integer results
DfaBuilder<Integer> builder = new DfaBuilder<>();

//Lets say you have a list of keywords:
for (int i=0; i<keywords.size(); ++i)
{
    Pattern pat = Pattern.maybeRepeat(CharRange.ALL)
        .then(keywords.get(i));
    builder.addPattern(pat, i);  //when this pattern matches, we get i out
}
DfaState<Integer> startState = builder.build(null);

然后像这样使用它:

DfaState<Integer> st = startState;
for (... each input character c ...)
{
    st = st.getNextState(c);
    //if this is non-null, then it's the index of the matched keyword
    //in the keywords list
    Integer match = st.getMatch();
}

【讨论】:

  • 你能举个例子吗?我无法理解您在说什么。
  • 我也有多个关键字。我需要多次致电then吗?
  • 我在答案中添加了一个示例
  • 好的,所以我知道它可以找到模式并返回一个可以与命令关联的对象。除了正常的命令外,我还需要从输入中检索数据。我可以使用Pattern 来查找数据的正则表达式模式,它必须与Lane\s\d\s*\d.\d\d\d\d 匹配,这样会找到类似Lane 5 1.2345 的内容。我需要获取车道编号(在本例中为 5)和时间(在本例中为 1.2345)。据我所知,我只能匹配一个模式并返回一个静态值。
  • 如果您的解析要求都这么简单,那么您就可以了,但是如果它们变得过于复杂,那么您可能不得不考虑构建一个真正的解析器。但是,对于这种事情,您通常要做的是将每个命令的模式与解析相关值的过程相关联。对于 MATCHRESULT,我通常不会使用 Integer,而是使用带有抽象方法的 Enum 来进行解析过程,每个枚举值都将实现该解析过程。 LANE 过程可以返回 2 个空格序列,创建一个字符串,然后拆分它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-17
  • 2015-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多