【问题标题】:Java 8 lambda expression callback type when parsing strings with regex使用正则表达式解析字符串时的 Java 8 lambda 表达式回调类型
【发布时间】:2013-11-22 21:09:05
【问题描述】:

我想编写一个函数,它可以将字符串与正则表达式匹配,并以所有组匹配作为参数执行回调。

我想出了这个并且它有效:

 private static void parse(String source, String regex, 
                                  Consumer<String[]> callback) {      
        //convert regex groups 1..n into integer array 0..n-1 and call 
        //consumer callback with this array
        Matcher m = Pattern.compile(regex).matcher(source);
        String[] ret = new String[m.groupCount()];
        if (m.matches()) {
            for (int i=0; i<m.groupCount(); i++) {
                ret[i] = m.group(1+i);
            }
            callback.accept(ret);
        }
    }

你可以这样做

parse("Add 42,43", "Add (\\d+?),(\\d+?)", p -&gt; processData(p[0],p[1]));

我最想做的就是这样

parse("Add 42,43", "Add (\\d+?),(\\d+?)", (x,y) -&gt; processData(x,y));

什么是最优雅的方式?我唯一能想到的就是用 1..n 参数声明多个功能接口,并使用覆盖来处理它。有没有更好的想法,也许需要反思?

【问题讨论】:

  • 我不完全确定你在追求什么,但似乎 varargs 和 lambda 不能以你想要的方式混合。为了使用 lambda,目标类型必须是函数式接口,其单个方法具有固定数量的参数,在编译时确定。问题的根源在于直到运行时才知道正则表达式中有多少组。如果只有一组,如何调用processData,因为它似乎需要两个参数?
  • 实际上,我认为,调用者确实知道正则表达式中有多少组,并且方法覆盖的想法可能有效。只是没有一种方法。

标签: java lambda java-8


【解决方案1】:

据我了解,问题是是否有用于从数组初始化元组的语法糖,即:

 val (hour, minutes, seconds) = new String[]{"12", "05", "44"};

...除了它隐藏在 lambda 参数声明中。

据我所知,Java 8 中没有这样的语法,您的方法似乎是最方便的。但是,在 Scala 中有:Is there a way to initialize multiple variables from array or List in Scala?。

Scala 中也有类似的指令:

 scala> val s = "Add 42,43"
 scala> val r = "Add (\\d+?),(\\d+?)".r
 scala> val r(x,y) = s
 x: String = 42
 y: String = 43

【讨论】:

  • 感谢 Scala 中的解决方案。不知道这招。我将尝试看看在 Java 8 中是否有其他可能的解决方案。不是元组初始化,而是可能用 1,2 或 3 个参数覆盖,然后诉诸数组以获得更多。它将涵盖很多简单的解析案例。
  • 认为重写是可行的方法,我正要编写一些骨架代码,但有点懒惰。 (我也想知道 java 的新类型推理系统有多灵活)。
【解决方案2】:

由于我现在已经为自己解决了,所以我将在这里发布我想出的解决方案。如果有人提出更好的建议,也许是方法链或更通用,我很乐意给予答复。

你可以像这样使用下面的类:

Sring msg = "add:42,34";
ParseUtils.parse(msg, "add:(\\d+),(\\d+)", (int x,int y) -> simulator.add(x, y));
ParseUtils.parse(msg, "add:(\\d+),(\\d+)", simulator::add); //IntBiConsumer match
ParseUtils.parse(msg, "add:(.*?),", System.out::println);

这是类(我省略了琐碎的错误处理,如果不匹配则返回布尔值):

public class ParseUtils {

    @FunctionalInterface
    public interface Consumer { void accept(String s); }

    @FunctionalInterface
    public interface BiConsumer { void accept(String a, String b); }

    //... you can add TriConsumer etc. if you need to ...

    @FunctionalInterface  //conveniently parses integers
    public interface IntBiConsumer { void accept(int x, int y); }

    // implementations -----
    public static void parse(String src, String regex, Consumer callback) {
        callback.accept(parse(src, regex)[0]);
    }

    public static void parse(String src, String regex, BiConsumer callback) {
        String[] p = parse(src, regex);
        callback.accept(p[0],p[1]);
    }

    public static void parse(String src, String regex, 
                                                    IntBiConsumer callback) {
        String[] p = parse(src, regex);
        callback.accept(Integer.parseInt(p[0]), Integer.parseInt(p[1]));
    }

    public static String[] parse(String source, String pattern) {
        Pattern p = Pattern.compile(pattern);
        Matcher m = p.matcher(source);
        String[] ret = new String[m.groupCount()];
        if (m.matches()) {
            for (int i=0; i<m.groupCount(); i++) {
                ret[i] = m.group(1 + i);
            }
        }
        return ret;
    }

}

【讨论】:

    猜你喜欢
    • 2010-11-22
    • 2022-01-25
    • 2017-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-30
    • 2019-12-10
    相关资源
    最近更新 更多