【问题标题】:JAVA: Regexp on user-defined tokensJAVA:用户定义令牌上的正则表达式
【发布时间】:2013-04-05 11:39:16
【问题描述】:

我需要对一组用户定义的令牌运行正则表达式。

例如,我有一个这样的字符串: TOK3 TOK1 TOK2 TOK2 TOK4 TOK3 // 示例字符串

并使用这样的正则表达式: (TOK1|TOK2)+ // 正则表达式

我想在我的示例字符串中捕获标记序列:TOK1 TOK2 TOK2

现在,regexp 通常适用于一系列字符,所以我的问题略有不同,因为我的标记不是字符而是字符串。我的令牌可以由两个或多个字符组成。此外,我的软件应该能够检测到示例中的正则表达式与位置 (1, 4) 处的字符串匹配。

目前,我通过将每个标记映射到 ASCII 字母表中的字符并在删除空格后运行正则表达式来解决问题。

但是,我对这个解决方案并不完全满意,我想知道是否有更好的解决方案。谢谢!

编辑

正则表达式中的空格仅用于分隔标记。它们并不意味着标记之间必须有空格。

【问题讨论】:

  • 您能否通过示例/代码解释自定义标记的确切含义?像一个字符串集合?
  • 基本上模式不是字符序列而是字符串序列。可能正确的术语不是定制的,而是定制的。我很抱歉。但是,每个标记都应该被视为一个原子实体作为一个字符。
  • 为什么要先删除空格而不是将它们包含在正则表达式中?
  • 因为在我的实现中,我将每个标记映射到一个字符,然后将映射的正则表达式与映射匹配的字符串进行匹配。例如模式(TOK1|TOK2)+ 被映射为例如"(a|b)+"。而示例字符串映射到"c a b b d c"。后者,在删除空格之后是"cabbdc"。现在模式可以匹配示例字符串了。

标签: java regex customization


【解决方案1】:

按照您的示例,这应该可以正常工作:

(?:(?:TOK1|TOK2|...)(?: |$))+

Matcher#start 方法会告诉你比赛开始的位置。

不过,看起来很简单,我觉得我在你的问题中遗漏了一些东西......

【讨论】:

  • 但是 start() 方法和 end() 方法会给我与模式匹配的第一个字符的位置,而不是标记位置。虽然我可以分割字符串并计算匹配左侧剩余的令牌数量...... :)
  • 如果令牌的位置也是第一个字符的位置,不是吗?如果你想要每个令牌的位置,我猜TOK1|TOK2 会更容易。一个标记可以是另一个标记的某个子字符串吗?
  • 并非如此。例如,如果我们考虑字符,则模式在 (5, 19) 匹配,但如果我们考虑令牌(并忽略空格),则匹配位置 (1, 4)。在某些情况下,标记可能是其他标记的子字符串。
  • 好的,我明白你的意思了。我会考虑的。 (你目前如何替换标记?你不会被子字符串愚弄吗?)
  • 实际上,我有空格(在模式和示例字符串中)显示标记的边界。这样,映射过程就被简化了。比我使用查找表(令牌(字符串)-> 字符)。
【解决方案2】:

如何存储所有空格的位置并使用它来将字符串位置转换为标记位置?

远没有直接的正则表达式那么优雅,但这是一个想法。

TreeMap<Integer, Integer> spaces = new TreeMap<Integer, Integer>();
String regex = "(?<=^| )((TOK1|TOK2)( |$))+";
String str = "TOK3 TOK1 TOK2 TOK2 TOK4 TOK3";
int c = 0;
spaces.put(0, 0);
for (int i = 0; i < str.length(); i++)
{
   if (str.charAt(i) == ' ')
     spaces.put(i, ++c);
}
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(str);
while (m.find()) {
   System.out.println(m.group());
   System.out.println("start = " + spaces.floorEntry(m.start()).getValue());
   System.out.println("finish = " + spaces.floorEntry(m.end()).getValue());
}

另一个选项是String.split:

String str = "TOK3 TOK1 TOK2 TOK2 TOK4 TOK3";
String[] arr = str.split(" "); // maybe consider using \\s or \\s+ instead
int start = -1;
String match = "";
for (int i = 0; i < arr.length; i++)
{
   if (arr[i].matches("(TOK1|TOK2)"))
   {
      if (start == -1)
         start = i;
      match += ((match.length() != 0) ? " " : "") + arr[i];
   }
   else if (start != -1)
   {
      System.out.println(match);
      System.out.println("start = " + start);
      System.out.println("finish = " + i);
      match = "";
      start = -1;
   }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-29
    • 2013-03-07
    • 1970-01-01
    相关资源
    最近更新 更多