Как определить, является ли число простым с регулярным выражением?
Я нашел следующий пример кода для Java на RosettaCode:
public static boolean prime(int n) {
return !new String(new char[n]).matches(".?|(..+?)1+");
}
- Я не знаю Java в частности, но понять все аспекты этого фрагмента, за исключением самого регулярного выражения
- у меня есть базовые базовые знания о регулярных выражениях, как вы найдете его во встроенных функциях PHP
Как .?|(..+?)1+ простые числа матч?
4 ответов:
Вы сказали, что понимаете эту часть, но просто чтобы подчеркнуть, генерируемая строка имеет длину, равную указанному числу. Таким образом, строка имеет три символа, если и только если
n == 3..?первая часть регулярного выражения говорит:"любой символ, ноль или один раз". Итак, в принципе, есть ли ноль или один символ - или, согласно тому, что я упомянул выше,
n == 0 || n == 1. Если у нас есть совпадение, то верните отрицание этого. Это соответствует тому, что ноль и единица не являются главный.(..+?)\1+вторая часть регулярного выражения является немного сложнее, опираясь на группы и обратные ссылки. Группа-это что-либо в скобках, которое затем будет захвачено и сохранено механизмом регулярных выражений для последующего использования. Обратная ссылка-это сопоставленная группа, которая используется позже в том же регулярном выражении.
группа захватывает 1 символ, затем 1 или более любых символов. (Символ + означает один или несколько, но только из предыдущего символа или группы. Так что это не "два или четыре или шесть и т. д. символов", а "два или три и т. д.- В +? это похоже на+, но он пытается соответствовать как можно меньшему количеству символов. + обычно пытается сожрать всю строку, если это возможно, что плохо в этом случае, потому что это предотвращает работу части обратной ссылки.)
следующая часть-Ссылка: тот же набор символов (два или более), появляются снова. Упомянутая обратная ссылка появляется один или несколько раз.
так. Захваченная группа соответствует естественной количество захваченных символов (от 2 и далее). Сказал тогда группа появляется некоторое натуральное число раз (от 2 и далее). Если есть совпадение, это означает, что можно найти произведение двух чисел, больших или равных 2, которые соответствуют строке n-длины... это означает, что у вас есть составное n. Итак, снова верните отрицание успешного совпадения: n не является простым.
если совпадение не найдено, то вы не можете придумать свой продукт из двух натуральных чисел больше или равен 2... и у вас есть как не совпадение, так и простое число, следовательно, снова возвращение отрицания результата матча.
вы видите это сейчас? Это невероятно сложно (и вычислительно дорого!) но это также довольно просто в то же время, как только вы его получите. : -)
Я могу уточнить, если у вас есть дополнительные вопросы, например, о том, как разбор регулярных выражений на самом деле работает. Но я пытаюсь сохранить этот ответ прост Для сейчас (или так просто, как это может быть).
я объясню часть регулярного выражения за пределами тестирования примитивности: следующее регулярное выражение, учитывая
String sкоторый состоит из повторенияString tнаходитt.System.out.println( "MamamiaMamamiaMamamia".replaceAll("^(.*)\1+$", "") ); // prints "Mamamia"как это работает, что регулярное выражение захватывает
(.*)на, а потом видит, есть ли+следуя за ним. Используя^и$гарантирует, что совпадение должно быть всей строки.так что, в некотором смысле, нам дали
String s, который является "кратным"String t, и регулярное выражение найду такихt(как можно дольше, так какжадный).как только вы поймете, почему это регулярное выражение работает, то (игнорируя первый альтернативный вариант в регулярном выражении OP на данный момент) объясняя, как он используется для тестирования примитивности, просто.
- чтобы проверить примитивность
nсначала нужно создатьStringдлинойn(заполненный тем жеchar)- регулярное выражение захватывает a
Stringнекоторой длины (скажемk) в, и старается чтобы соответствовать+остальноеString
- если есть совпадение, то
nявляется правильным кратнымk, и поэтомуnне премьер.- если нет совпадения, то нет такого
kсуществует то, что делитnи главный
как
.?|(..+?)+простые числа матч?на самом деле, это не так! Это игр
Stringчья длина не является простой!
.?: первая часть чередования соответствуетStringдлиной0или1(не простой по определению)(..+?)+: вторая часть чередования, вариация регулярного выражения, объясненного выше, соответствуетStringдлинойnэто "кратное" aStringдлинойk >= 2(т. е.nявляется составным, а не простым).
- обратите внимание, что неохотно модификатор
?на самом деле не требуется для корректности, но это может помочь ускорить процесс, пытаясь меньшеkпервыйПримечание
!booleanоператор дополнения вreturnзаявление: это отрицаетmatches. Это когда регулярное выражение НЕ матчnпремьер! Это двойная отрицательная логика, поэтому неудивительно, что это сбивает с толку!!
упрощение
вот простой переписывание кода, чтобы сделать его более читабельным:
public static boolean isPrime(int n) { String lengthN = new String(new char[n]); boolean isNotPrimeN = lengthN.matches(".?|(..+?)\1+"); return !isNotPrimeN; }вышеизложенное по существу совпадает с исходным кодом Java, но разбито на несколько операторов с назначениями локальным переменным, чтобы сделать логику более понятной.
мы также можем упростить выражение, используя конечное повторение, следующим образом:
boolean isNotPrimeN = lengthN.matches(".{0,1}|(.{2,})\1+");опять дали
Stringдлинойn, заполненный тем жеchar,
.{0,1}проверяет еслиn = 0,1, а не премьер -(.{2,})+проверяет, является лиnявляется правильным кратнымk >= 2, а не премьер -за исключением неохотного модификатора
?on(опущено для ясности), приведенное выше регулярное выражение идентично оригиналу.
больше удовольствия регулярное выражение
следующее регулярное выражение использует аналогичную технику; оно должно быть образовательным:
System.out.println( "OhMyGod=MyMyMyOhGodOhGodOhGod" .replaceAll("^(.+)(.+)(.+)=(\1|\2|\3)+$", "! ! !") ); // prints "Oh! My! God!"посмотреть также
хороший трюк с регулярным выражением (хотя и очень неэффективный)... :)
регулярное выражение определяет не простые числа следующим образом:
N не является простым тогда и только тогда, когда N1.
вместо того, чтобы передавать простое цифровое представление N в механизм регулярных выражений, он подается с последовательностью длина N, состоящий из повторяющегося символа. Первая часть дизъюнкции проверяет наличие N=0 или N=1, а вторая ищет делитель K>1, используя обратная ссылка. Это заставляет механизм регулярных выражений найти некоторую непустую подпоследовательность, которая может быть повторена по крайней мере дважды, чтобы сформировать последовательность. Если такая подпоследовательность существует, это означает, что ее длина делит N, следовательно N не является простым числом.
/^1?$|^(11+?)+$/применить к числам после преобразования базы 1 (1=1, 2=11, 3=111, ...). Не простые числа будут соответствовать этому. Если он не совпадает,то это просто.
объяснение здесь.
Comments