Я нашел следующий пример кода для Java в RosettaCode :
public static boolean prime(int n) {
return !new String(new char[n]).matches(".?|(..+?)\\1+");
}
- Я не знаю конкретно Java, но понимаю все аспекты этого фрагмента, кроме самого регулярного выражения.
- У меня есть базовые или базовые знания о Regex, как вы находите его во встроенных функциях PHP.
Как соотносятся .?|(..+?)\\1+
простые числа?
!new String(new char[n]).matches(".?|(..+?)\\1+")
эквивалентно!((new String(new char[n])).matches(".?|(..+?)\\1+"))
.Ответы:
Вы сказали, что понимаете эту часть, но чтобы подчеркнуть, сгенерированная строка имеет длину, равную указанному числу. Таким образом, строка состоит из трех символов тогда и только тогда, когда
n == 3
.Первая часть регулярного выражения говорит: «любой символ, ноль или один раз». Таким образом , в принципе, есть ноль или один character-- или, за то , что я уже упоминал выше,
n == 0 || n == 1
. Если у нас есть совпадение, верните отрицание этого. Это соответствует тому факту, что ноль и единица НЕ являются простыми числами.Вторая часть регулярного выражения немного сложнее, полагаясь на группы и обратные ссылки. Группа - это все, что указано в скобках, которое затем будет захвачено и сохранено обработчиком регулярных выражений для дальнейшего использования. Обратная ссылка - это сопоставленная группа, которая используется позже в том же регулярном выражении.
Группа захватывает 1 персонажа, затем 1 или более персонажей. (Символ + означает один или несколько, но ТОЛЬКО предыдущего символа или группы. Таким образом, это не «два, четыре или шесть и т. Д. Символов», а скорее «два или три и т. Д.» Знак +? Похож на +, но он пытается сопоставить как можно меньше символов. + обычно пытается сожрать всю строку, если может, что в данном случае плохо, потому что это мешает работе части обратной ссылки.)
Следующая часть - это обратная ссылка: тот же набор символов (два или более) появляется снова. Указанная обратная ссылка появляется один или несколько раз.
Так. Захваченная группа соответствует натуральному количеству захваченных символов (начиная с 2). Затем указанная группа появляется некоторое натуральное число раз (также начиная с 2). Если есть совпадение, это означает, что можно найти произведение двух чисел, больших или равных 2, которые соответствуют строке длиной n ... что означает, что у вас есть составное n. Итак, снова верните отрицание успешного совпадения: n НЕ является простым.
Если совпадение не может быть найдено, то вы не можете найти произведение двух натуральных чисел, больших или равных 2 ... и у вас есть как несоответствие, так и простое число, следовательно, снова возвращается отрицание. результата матча.
Теперь вы это видите? Это невероятно сложно (и дорого с точки зрения вычислений!), Но в то же время это довольно просто, как только вы это получите. :-)
Я могу уточнить, если у вас есть дополнительные вопросы, например, о том, как на самом деле работает синтаксический анализ регулярных выражений. Но пока я стараюсь, чтобы этот ответ был простым (или настолько простым, насколько это вообще возможно).
источник
Я объясню часть регулярного выражения вне проверки простоты: следующее регулярное выражение,
String s
которое состоит из повторяющихсяString t
, находитt
.Как это работает в том , что регулярные выражения захватывает
(.*)
в\1
, а затем видит , если там\1+
после него. Использование^
и$
гарантирует, что совпадение должно быть для всей строки.Итак, в некотором роде нам дано
String s
, что является "кратным"String t
, и регулярное выражение найдет такоеt
(самое длинное из возможных, поскольку\1
является жадным).Как только вы поймете, почему это регулярное выражение работает, тогда (игнорируя первую альтернативу в регулярном выражении OP) просто объяснить, как оно используется для проверки простоты.
n
, сначала сгенерируйтеString
длинуn
(заполненную таким жеchar
)String
некоторую длину (скажемk
) в\1
и пытается сопоставить\1+
с остальной частьюString
n
является правильным кратнымk
, и, следовательноn
, не является простым.k
делителей не существуетn
иn
, следовательно, является простым.На самом деле это не так! Это соответствует
String
, длина которого не простой!.?
: Первая часть чередующихся совпаденийString
длины0
или1
(НЕ простых по определению)(..+?)\1+
: Вторая часть чередования, вариант регулярного выражения, описанного выше, совпаденияString
длины,n
которая "кратна"String
длинеk >= 2
(т.е.n
является составной, а НЕ простым).?
самом деле не нужен для правильности, но он может помочь ускорить процесс, попробовавk
сначала уменьшитьОбратите внимание на
!
boolean
оператор дополнения вreturn
заявлении: он отменяетmatches
. Это когда регулярное выражение НЕ совпадает,n
оно простое! Это двойная отрицательная логика, поэтому неудивительно, что это сбивает с толку !!упрощение
Вот простая переписывание кода, чтобы сделать его более читабельным:
Вышеупомянутое, по сути, такое же, как исходный код Java, но разбито на несколько операторов с присвоениями локальным переменным, чтобы упростить понимание логики.
Мы также можем упростить регулярное выражение, используя конечное повторение, следующим образом:
Опять же, учитывая
String
длинуn
, заполненную тем же самымchar
,.{0,1}
проверяетn = 0,1
, НЕ премьер(.{2,})\1+
проверяет,n
является ли правильным кратнымk >= 2
, НЕ простымЗа исключением модификатора reluctant
?
on\1
(опущен для ясности), приведенное выше регулярное выражение идентично оригиналу.Более забавное регулярное выражение
В следующем регулярном выражении используется похожая техника; он должен быть образовательным:
Смотрите также
источник
[Populist]
от этого.Хороший трюк с регулярным выражением (хотя и очень неэффективный) ... :)
Регулярное выражение определяет непростые числа следующим образом:
N не является простым, если и только если N <= 1 ИЛИ N делится на некоторое K> 1.
Вместо того, чтобы передавать простое цифровое представление N механизму регулярных выражений, ему передается последовательность длиной N, состоящая из повторяющегося символа. Первая часть дизъюнкции проверяет N = 0 или N = 1, а вторая ищет делитель K> 1, используя обратные ссылки. Это заставляет механизм регулярных выражений находить некоторую непустую подпоследовательность, которую можно повторить как минимум дважды, чтобы сформировать последовательность. Если такая подпоследовательность существует, это означает, что ее длина делит N, следовательно, N не является простым.
источник
Применяется к числам после преобразования в базу 1 (1 = 1, 2 = 11, 3 = 111, ...). Нестандартные числа будут соответствовать этому. Если он не совпадает, он первичный.
Объяснение здесь .
источник