Pandigital Regex? - PullRequest
       6

Pandigital Regex?

5 голосов
/ 17 апреля 2009

Какое регулярное выражение проверяет, является ли строка пандигитальной (содержит все цифры от 1 до 9 ровно один раз)?

Например:

123456789
891364572

Но не:

11234556789
25896471

Я знаю, как это сделать без регулярных выражений, но я не смог сформировать регулярное выражение для него.

Спасибо.

Это не домашняя работа.

Ответы [ 5 ]

15 голосов
/ 17 апреля 2009

Короткий и сладкий, с отрицательным взглядом:

/^(?!.*([1-9]).*\1)[1-9]{9}$/
  • [1-9] - класс символов для ненулевых цифр - эквивалент [123456789]
  • .* соответствует любой строке любой длины.
  • .*([1-9]).*\1.* соответствует любой строке, которая содержит как минимум два вхождения одной и той же ненулевой цифры
    • ненулевая цифра сопоставляется и захватывается ([1-9])
    • повтор этой ненулевой цифры соответствует \1, обратная ссылка соответствует первому захваченному совпадению.
    • .* соответствует произвольному заполнению до и между ненулевой цифрой и ее повторением.
  • (?!<i><pattern></i>) соответствует любой позиции, где содержащийся шаблон не соответствует . Это отрицательный прогноз , так как он соответствует только позиции в строке и не потребляет ничего из этого - просто смотрит вперед, чтобы сравнить его с содержащимся шаблоном. *
  • [1-9]{9} соответствует девяти ненулевым цифрам.
    • <i><pattern></i>{9} означает соответствие предыдущему шаблону 9 раз.
  • ^<i><pattern></i>$ соответствует любой строке, которая точно соответствует содержащемуся шаблону (а не содержит подстроку, которая соответствует шаблону)
    • ^ соответствует позиции в начале строки ИЛИ начале строки
    • $ соответствует позиции в конце строки ИЛИ конце строки

Итак, мы проверяем, чтобы он не повторял никаких цифр, а затем проверяем, что это только цифры. Поскольку он состоит из 9 цифр и не повторяется, все должно появиться ровно один раз. Это принцип голубиного отверстия на работе!

Синтаксис для вашего конкретного механизма регулярных выражений может отличаться. Выше приведен PCRE (поддерживается в Perl, Ruby и нескольких других языках). Регулярные выражения Posix имеют немного другой синтаксис. Не все движки поддерживают негативные запросы, но большинство поддерживают обратные ссылки. Они также не являются частью определения формальных теоретических регулярных выражений, но очень удобны.

4 голосов
/ 17 апреля 2009

Regex не совсем лучший инструмент для работы здесь, но вот вам:

^(?=[^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 голосов
/ 17 апреля 2009

Если это не домашняя работа, вы не должны использовать 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
1 голос
/ 17 апреля 2009

Это было бы гораздо проще сделать в процедурном коде, циклически проходя по каждому символу и помечая их в массиве, или это домашняя работа?

0 голосов
/ 17 апреля 2009

<code>
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]));
}

что-то подобное может сработать. не удосужился проверить это.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...