如何迭代符合regexp的字符串

时间:2013-07-03 16:24:24

标签: java regex algorithm iterator

实现一个类(在Java中)的最简单方法是什么,它将作为符合给定正则表达式的所有值的集合的迭代器?

假设我有一个这样的课程:

public class RegexpIterator
{
  private String regexp;

  public RegexpIterator(String regexp) {
    this.regexp = regexp;
  }

  public abstract boolean hasNext() {
    ...
  }

  public abstract String next() {
    ...
  }
}

我该如何实施?该类假定所有符合值的集合采用某种线性排序,而next()方法在第i次调用时应返回第i个值。

理想情况下,该解决方案应支持完整的regexp语法(由Java SDK支持)。


为避免混淆,请注意,该类不应在给定字符串上迭代给定正则表达式的匹配。相反,它应该(最终)枚举符合正则表达式的所有字符串值(即匹配器的matches()方法可以接受),而不作为参数给出任何其他输入字符串。


为了进一步澄清这个问题,让我们举一个简单的例子。

RegexpIterator it = new RegexpIterator("ab?cd?e");
while (it.hasNext()) {
  System.out.println(it.next());
}

此代码段应具有以下输出(行的顺序不相关,即使首先列出较短字符串的解决方案也是首选。)

ace
abce
ecde
abcde

请注意,对于某些regexp,例如ab[A-Z]*cd,类要迭代的值集是无限的。在这些情况下,前面的代码片段会永远运行。

2 个答案:

答案 0 :(得分:3)

你需要实现一个课程吗?这种模式效果很好:

    Pattern p = Pattern.compile("[0-9]+");
    Matcher m = p.matcher("123, sdfr 123kjkh 543lkj ioj345ljoij123oij");
    while (m.find()) {
        System.out.println(m.group());
    }

输出:

123
123
543
345
123

获得更广泛的解决方案:

public static List<String> getMatches(String input, String regex) {
    List<String> retval = new ArrayList<String>();
    Pattern p = Pattern.compile(regex);
    Matcher m = p.matcher(input);
    while (m.find()) {
        retval.add(m.group());
    }
    return retval;
}

然后可以像这样使用:

public static void main(String[] args) {
    List<String> matches = getMatches("this matches _all words that _start _with an _underscore", "_[a-z]*");
    for (String s : matches) { // List implements the 'iterable' interface
        System.out.println(s);
    }
}

产生这个:

_all
_start
_with
_underscore

有关Matcher类的更多信息,请访问:http://docs.oracle.com/javase/6/docs/api/java/util/regex/Matcher.html

答案 1 :(得分:0)

这是另一个工作示例。它可能会有所帮助:

public class RegxIterator<E> implements RegexpIterator {

private Iterator<E> itr = null;

public RegxIterator(Iterator<E> itr, String regex) {
    ArrayList<E> list = new ArrayList<E>();
    while (itr.hasNext()) {
        E e = itr.next();
        if (Pattern.matches(regex, e.toString()))
            list.add(e);
    }
    this.itr = list.iterator();
}

@Override
public boolean hasNext() {
    return this.itr.hasNext();
}

@Override
public String next() {
    return this.itr.next().toString();
}

}

如果要将其用于其他数据类型( Integer,Float 等或 toString()有意义的其他类),请声明 next() 返回 Object 而不是 String 。然后,您可以在返回值上执行typeCast以返回实际类型。