用于匹配扑克牌手(Java)的正则表达式

3

作为一个正则表达式初学者,我需要一个可以匹配特定扑克牌型(Full House - 包含三张同点数和两张另一种点数的牌)的正则表达式。它应该能够识别所有牌值(23456789TJQKA)和花色(SHDC)的任意顺序,并将其识别为Full House。

如果您认为我应该使用其他工具,请告诉我,因为我甚至不确定正则表达式是否适合这个问题 :)

一个示例字符串可能如下所示:

"KD KC AH AC AD"

(方块K、梅花K、红桃A、梅花A、方块A)

我已经想出了这个丑陋的正则表达式:

(?=.*(([2-9TJQKA])[SHDC]).*\2[SHDC].*\2[SHDC])(?=.*(?!\2)(([2-9TJQKA])[SHDC]).*\4[SHDC].*\4[SHDC]).*

但它似乎没有完成任务。

你得到了什么字符串?你需要得到什么? - Eduardo Lynch Araya
4
我不会用正则表达式实现这个,你可以编写一个简单的方法来检查手牌是否只拥有两种不同的牌面并且其中一种牌面出现了恰好三次。这应该是一个容易编写和维护的方法,此外因为不使用正则表达式,性能会更好。 - Nir Alfasi
使用String类的matches()方法来匹配整个字符串,但根据regexr.com的结果,我没有匹配到任何内容。 - Boris Grunwald
你说得可能是对的 :) 只是每当我需要进行一些高级字符串匹配时,我总是认为正则表达式是最好的选择。 - Boris Grunwald
2个回答

3

这应该匹配“full houses”:(编辑:实际上只是您原始的正则表达式修复忽略了花色)

(?=.*([2-9TJQKA])[SHDC].*\1[SHDC].*\1[SHDC])(?=.*((?!\1)[2-9TJQKA])[SHDC].*\2[SHDC])

它使用第一个 lookahead 查找“3”序列。第二个 lookahead 查找“2”序列,其中包含负向先行断言以避免重复匹配。这个正则表达式完全由两个 lookahead 组成,它们防止了如果我们实际匹配(并移动指针)任何字符而引起的问题 - 这两个子模式都可以在字符串中的任何位置匹配。
在线演示请点击此处

1

你可以使用Guava Multimap而不是正则表达式,检查是否仅有两个不同的等级,然后检查这些等级中是否有一个等级具有3个花色。

public class Foo {
    public static void main(String[] a) {
        String s = "KD KC AH AC AD";
        Splitter splitter = Splitter.on(' ');
        System.out.println(checkFullHouse(splitter.split(s)));
    }

    private static boolean checkFullHouse(Iterable<String> in) {
        Multimap<String, Object> m = ArrayListMultimap.create();
        Splitter splitter = Splitter.fixedLength(1);
        in.forEach(s -> {
            List<String> l = Lists.newArrayList(splitter.split(s));
            m.put(l.get(0), l.get(1));
        });
        return m.keySet().size() == 2 && (int) m.keySet().stream().filter(v -> m.get(v).size() == 3).count() == 1;
    }
}

我以前没有使用过Multimap,但这看起来更简单。我会研究一下 :) - Boris Grunwald
1
不要使用关键字assert来验证输入!另外,如果您使用Guava,请优先使用Splitter类而不是方法String::split(因为split使用正则表达式...如果您想避免它们,就避免它们;)。 - Olivier Grégoire
1
修改了@OlivierGrégoire - baao

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接