Regex to calculate straight poker hand - Using ASCII CODE

老子叫甜甜 提交于 2019-12-22 08:20:08

问题


In another question I learned how to calculate straight poker hand using regex (here).

Now, by curiosity, the question is: can I use regex to calculate the same thing, using ASCII CODE?

Something like:

regex: [C][C+1][C+2][C+3][C+4], being C the ASCII CODE (or like this)

Matches: 45678, 23456

Doesn't matches: 45679 or 23459 (not in sequence)


回答1:


Your main problem is really going to be that you're not using ASCII-consecutive encodings for your hands, you're using numerics for non-face cards, and non-consecutive, non-ordered characters for face cards.

You need to detect, at the start of the strings, 2345A, 23456, 34567, ..., 6789T, 789TJ, 89TJQ, 9TJQK and TJQKA.

These are not consecutive ASCII codes and, even if they were, you would run into problems since both A2345 and TJQKA are valid and you won't get A being both less than and greater than the other characters in the same character set.

If it has to be done by a regex, then the following regex segment:

(2345A|23456|34567|45678|56789|6789T|789TJ|89TJQ|9TJQK|TJQKA)

is probably the easiest and most readable one you'll get.




回答2:


There is no regex that will do what you want as the other answers have pointed out, but you did say that you want to learn regex, so here's another meta-regex approach that may be instructional.

Here's a Java snippet that, given a string, programmatically generate the pattern that will match any substring of that string of length 5.

    String seq = "ABCDEFGHIJKLMNOP";
    System.out.printf("^(%s)$",
        seq.replaceAll(
            "(?=(.{5}).).",
            "$1|"
        )
    );

The output is (as seen on ideone.com):

^(ABCDE|BCDEF|CDEFG|DEFGH|EFGHI|FGHIJ|GHIJK|HIJKL|IJKLM|JKLMN|KLMNO|LMNOP)$

You can use this to conveniently generate the regex pattern to match straight poker hands, by initializing seq as appropriate.


How it works

. metacharacter matches "any" character (line separators may be an exception depending on the mode we're in).

The {5} is an exact repetition specifier. .{5} matches exactly 5 ..

(?=…) is positive lookahead; it asserts that a given pattern can be matched, but since it's only an assertion, it doesn't actually make (i.e. consume) the match from the input string.

Simply (…) is a capturing group. It creates a backreference that you can use perhaps later in the pattern, or in substitutions, or however you see fit.

The pattern is repeated here for convenience:

     match one char
        at a time
           |
(?=(.{5}).).
\_________/
 must be able to see 6 chars ahead
 (capture the first 5)

The pattern works by matching one character . at a time. Before that character is matched, however, we assert (?=…) that we can see a total of 6 characters ahead (.{5})., capturing (…) into group 1 the first .{5}. For every such match, we replace with $1|, that is, whatever was captured by group 1, followed by the alternation metacharacter.

Let's consider what happens when we apply this to a shorter String seq = "ABCDEFG";. The denotes our current position.

=== INPUT ===                                    === OUTPUT ===

 A B C D E F G                                   ABCDE|BCDEFG
↑
We can assert (?=(.{5}).), matching ABCDEF
in the lookahead. ABCDE is captured.
We now match A, and replace with ABCDE|

 A B C D E F G                                   ABCDE|BCDEF|CDEFG
  ↑
We can assert (?=(.{5}).), matching BCDEFG
in the lookahead. BCDEF is captured.
We now match B, and replace with BCDEF|

 A B C D E F G                                   ABCDE|BCDEF|CDEFG
    ↑
Can't assert (?=(.{5}).), skip forward

 A B C D E F G                                   ABCDE|BCDEF|CDEFG
      ↑
Can't assert (?=(.{5}).), skip forward

 A B C D E F G                                   ABCDE|BCDEF|CDEFG
        ↑
Can't assert (?=(.{5}).), skip forward

       :
       :

 A B C D E F G                                   ABCDE|BCDEF|CDEFG
              ↑
Can't assert (?=(.{5}).), and we are at
the end of the string, so we're done.

So we get ABCDE|BCDEF|CDEFG, which are all the substrings of length 5 of seq.

References

  • regular-expressions.info/Dot, Repetition, Grouping, Lookaround



回答3:


Something like regex: [C][C+1][C+2][C+3][C+4], being C the ASCII CODE (or like this)

You can not do anything remotely close to this in most regex flavors. This is simply not the kinds of patterns that regex is designed for.

There is no mainstream regex pattern that will succintly match any two consecutive characters that differ by x in their ASCII encoding.


For instructional purposes...

Here you go (see also on ideone.com):

    String alpha = "ABCDEFGHIJKLMN";
    String p = alpha.replaceAll(".(?=(.))", "$0(?=$1|\\$)|") + "$";

    System.out.println(p);
    // A(?=B|$)|B(?=C|$)|C(?=D|$)|D(?=E|$)|E(?=F|$)|F(?=G|$)|G(?=H|$)|
    // H(?=I|$)|I(?=J|$)|J(?=K|$)|K(?=L|$)|L(?=M|$)|M(?=N|$)|N$

    String p5 = String.format("(?:%s){5}", p);

    String[] tests = {
        "ABCDE",    // true
        "JKLMN",    // true
        "AAAAA",    // false
        "ABCDEFGH", // false
        "ABCD",     // false
        "ACEGI",    // false
        "FGHIJ",    // true
    };
    for (String test : tests) {
        System.out.printf("[%s] : %s%n",
            test,
            test.matches(p5)
        );
    }

This uses meta-regexing technique to generate a pattern. That pattern ensures that each character is followed by the right character (or the end of the string), using lookahead. That pattern is then meta-regexed to be matched repeatedly 5 times.

You can substitute alpha with your poker sequence as necessary.

Note that this is an ABSOLUTELY IMPRACTICAL solution. It's much more readable to e.g. just check if alpha.contains(test) && (test.length() == 5).

Related questions

  • How does the regular expression (?<=#)[^#]+(?=#) work?



回答4:


SOLVED!

See in http://jsfiddle.net/g48K9/3

I solved using closure, in js.

String.prototype.isSequence = function () {
    If (this == "A2345") return true; // an exception
    return this.replace(/(\w)(\w)(\w)(\w)(\w)/, function (a, g1, g2, g3, g4, g5) {
        return    code(g1) == code(g2) -1 &&
                code(g2) == code(g3) -1 &&
                code(g3) == code(g4) -1 &&
                code(g4) == code(g5) -1;
    })
};

function code(card){
    switch(card){
        case "T": return 58;
        case "J": return 59;
        case "Q": return 60;
        case "K": return 61;
        case "A": return 62;
        default: return card.charCodeAt();
    }
}


test("23456");
test("23444");
test("789TJ");
test("TJQKA");
test("8JQKA");

function test(cards) {
    alert("cards " + cards + ": " + cards.isSequence())
}

Just to clarify, ascii codes:

ASCII CODES:

2 = 50
3 = 51
4 = 52
5 = 53
6 = 54
7 = 55
8 = 56
9 = 57
T = 84 -> 58
J = 74 -> 59
Q = 81 -> 60
K = 75 -> 61
A = 65 -> 62


来源:https://stackoverflow.com/questions/3482151/regex-to-calculate-straight-poker-hand-using-ascii-code

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!