Pandigital Regex?

时间:2009-04-17 01:57:25

标签: regex

什么是正则表达式验证字符串是否为pandigital(包含1到9的所有数字一次)?

例如:

123456789
891364572

但不是:

11234556789
25896471

我知道如何在没有正则表达式的情况下执行此操作,但我无法为其创建正则表达式。

感谢。

这不是作业。

5 个答案:

答案 0 :(得分:15)

简短而甜蜜,使用负向前瞻:

/^(?!.*([1-9]).*\1)[1-9]{9}$/
  • [1-9]是非零数字的字符类 - 相当于[123456789]
  • .*匹配任何长度的任何字符串。
  • .*([1-9]).*\1.*匹配任何包含至少两次相同非零数字的字符串
    • ([1-9])
    • 匹配并捕获非零数字
    • 重复该非零数字与\1匹配,反向引用与第一次捕获的匹配相匹配。
    • .*匹配之前的任意填充,以及非零数字与其重复之间的匹配。
  • (?!<pattern>)匹配包含的模式匹配的任何位置。这是一个否定前瞻,因为它只匹配字符串中的位置,并且不会消耗任何一个 - 只是向前看以将其与包含的模式进行比较。
  • [1-9]{9}匹配九个nonzeo数字。
    • <pattern>{9}表示匹配前面的模式9次。
  • ^<pattern>$匹配与包含的模式完全匹配的任何字符串(而不是包含与模式匹配的子字符串)
    • ^匹配字符串开头的位置或行的开头
    • $匹配字符串末尾的位置或行的结尾

如此组合,我们检查以确保它不重复任何数字,然后我们检查它只是数字。因为它长9位,没有重复,所以必须只显示一次。那就是pigeonhole principle正在发挥作用!

特定正则表达式引擎的语法可能有所不同。以上是PCRE(Perl,Ruby和一堆不同的其他语言支持)。 Posix regular expressions语法略有不同。并非所有引擎都支持负向前瞻,但大多数都支持反向引用。它们都不是正式理论正则表达式定义的一部分,但非常方便。

答案 1 :(得分:4)

正则表达式并不是这里工作的最佳工具,但是你去了:

^(?=[^1]*1[^1]*$)(?=[^2]*2[^2]*$)(?=[^3]*3[^3]*$)(?=[^4]*4[^4]*$)(?=[^5]*5[^5]*$)(?=[^6]*6[^6]*$)(?=[^7]*7[^7]*$)(?=[^8]*8[^8]*$)(?=[^9]*9[^9]*$)[1-9]+$

(?= )是一个先见之明。它实际上并不适合正则表达式的描述,因为它没有描述常规语言。

答案 2 :(得分:2)

如果不是作业,则不应使用RE。以下C代码应该是一个良好的开端。

#include <stdio.h>
int isPandigital (char *inputStr) {
    /* Initial used states of false. */
    char used[] = {0,0,0,0,0,0,0,0,0,0};

    int count = 0;
    char ch;

    /* Process each character in string. */

    while ((ch = *inputStr++) != '\0') {
        /* Non-numeric, bad. */
        if ((ch < '0') || (ch > '9')) {
            return 0;
        }

        /* Too many, bad. */
        if (++count > 9) {
            return 0;
        }

        /* Multiples, bad. */
        if (used[ch - '0']) {
            return 0;
        }

        /* Store fact that this one's been used. */
        used[ch - '0'] = 1;
    }

    /* Good or bad depending on how many we've had. */
    return (count == 9);
}

int main (int argCount, char *argVar[]) {
    int i;
    for (i = 1; i < argCount; i++) {
        if (isPandigital (argVar[i])) {
            printf ("'%s' is pandigital\n", argVar[i]);
        } else {
            printf ("'%s' is NOT pandigital\n", argVar[i]);
        }
    }
    return 0;
}

使用您的测试数据:

$ pandigital 123456789 891364572 11234556789 25896471

我们得到以下结果:

'123456789' is pandigital
'891364572' is pandigital
'11234556789' is NOT pandigital
'25896471' is NOT pandigital

答案 3 :(得分:1)

这在程序代码中更容易做,循环遍历每个字符并在数组中标记它们......或者这是一些功课?

答案 4 :(得分:0)


bool chk(string s, int idx, set sofar) {
  return index == s.length ? true : isdigit(s[idx]) && !sofar.count(s[idx]) && chk(s,++idx,sofar.insert(s[idx]));
}

像这样的东西可以工作。没有被打扰检查它。