RosettaCode 에서 Java에 대한 다음 코드 예제를 찾았습니다 .
public static boolean prime(int n) {
return !new String(new char[n]).matches(".?|(..+?)\\1+");
}
- 특히 Java를 모르지만 정규 표현식 자체를 제외 하고이 스 니펫의 모든 측면을 이해합니다.
- 내장 PHP 함수에서 Regex에 대한 기본 지식을 습득했습니다.
.?|(..+?)\\1+
소수 는 어떻게 일치합니까?
답변
이 부분을 이해한다고 말했지만 강조하기 위해 생성 된 문자열의 길이는 제공된 수와 같습니다. 따라서 문자열에는 if 만있는 경우 3 개의 문자가 n == 3
있습니다.
.?
정규식의 첫 부분은 “모든 문자, 0 번 또는 1 번”이라고 말합니다. 따라서 기본적으로 0 또는 1 문자가 있습니까? 또는 위에서 언급 한대로 n == 0 || n == 1
. 우리가 일치하면 그 부정을 반환합니다. 이것은 0과 1이 소수가 아니라는 사실과 일치합니다.
(..+?)\\1+
정규식의 두 번째 부분은 그룹과 역 참조에 의존하는 조금 까다 롭습니다. 그룹은 괄호 안에있는 항목으로, 나중에 사용할 수 있도록 정규식 엔진에서 캡처하고 저장합니다. 역 참조는 나중에 동일한 정규식에서 사용되는 일치 그룹입니다.
그룹은 1 개의 문자를 캡처 한 다음 1 개 이상의 문자를 캡처합니다. (+ 문자는 하나 이상의 문자를 의미하지만 이전 문자 또는 그룹에만 해당됩니다. 따라서 “2 또는 4 또는 6 등 문자”가 아니라 “2 또는 3 등”입니다. +?는 +와 비슷하지만 +와 같습니다. 가능한 한 적은 수의 문자를 찾으려고합니다. + 일반적으로 가능한 경우 전체 문자열을 잡으려고 시도합니다.이 경우 역 참조 부분이 작동하지 않기 때문에이 경우에는 좋지 않습니다.)
다음 부분은 역 참조입니다. 동일한 문자 세트 (두 개 이상)가 다시 나타납니다. 상기 역 참조는 1 회 이상 나타난다.
그래서. 캡처 된 그룹은 캡처 된 자연 문자 수 (2 이상)에 해당합니다. 그런 다음이 그룹은 몇 번이나 자연스럽게 나타납니다 (2 이상). 일치하는 것이 있으면 n 길이 문자열과 일치하는 2보다 크거나 같은 두 숫자의 곱을 찾을 수 있음을 의미합니다. 이는 복합 n을 의미합니다. 다시 한 번, 성공적인 일치의 부정을 반환하십시오. n은 소수가 아닙니다.
일치하는 항목을 찾을 수 없으면 2보다 크거나 같은 두 개의 자연수를 가진 제품을 만들 수 없으며 불일치와 소수가 모두 있으므로 부정의 귀환 경기 결과.
이제 보입니까? 믿을 수 없을만큼 까다 롭고 계산 비용이 많이 듭니다.하지만 일단 얻으면 동시에 간단합니다. 🙂
정규식 구문 분석이 실제로 어떻게 작동하는지와 같은 추가 질문이 있으면 자세히 설명 할 수 있습니다. 그러나 나는이 대답을 지금 당장 간단하게 유지하려고 노력하고 있습니다.
답변
주어진 다음 정규식 : 나는 소수성 테스트의 정규식 부분 밖에 설명 할 것이다 String s
반복으로 구성 String t
, 발견을 t
.
System.out.println(
"MamamiaMamamiaMamamia".replaceAll("^(.*)\\1+$", "$1")
); // prints "Mamamia"
작동 방법은 정규식 캡처입니다 (.*)
에 \1
, 다음이 있다면보고 \1+
를 다음과 같습니다. 은 Using ^
및 $
보장하지만이 경기는 전체 문자열이어야.
그래서 어떤 식으로 우리 String s
는의 “다수”인을 부여 받았으며 String t
정규 표현식은 그런 것을 찾을 것입니다 t
(가장 \1
욕심이 많기 때문에 가능한 가장 길다 ).
이 정규식이 왜 작동하는지 이해하고 나면 우선 OP 테스트의 첫 번째 대안을 무시하고 우선 순위 테스트에 사용되는 방법을 간단하게 설명합니다.
- 의 우선도를 테스트하려면
n
먼저String
길이를 생성n
하십시오 (같은 것으로 채워짐char
) - 정규식 캡처는
String
약간의 길이 (말의k
에)\1
, 그리고 시도 일치하는\1+
의 나머지String
- 일치하는 경우
n
의 적절한 배수k
이며 따라서n
소수가 아닙니다. - 일치가 없습니다 경우, 그러한은
k
그 분할을 존재하지 않는n
, 그리고n
따라서 소수
- 일치하는 경우
.?|(..+?)\1+
소수 는 어떻게 일치합니까?
실제로는 그렇지 않습니다! 그것은 일치 String
길이가 NOT 소수!
.?
:String
길이 의 대체 일치 의 첫 번째 부분0
또는1
(정의에 의한 소수는 아님)(..+?)\1+
: 대체의 두 번째 부분, 위에서 설명한 정규 표현식의 변형은String
길이의n
“배”String
길이k >= 2
(즉n
소수가 아닌 복합) 의 길이 와 일치 합니다.- reluctant 수정자는
?
실제로 정확성을 위해 필요하지는 않지만 더 작은 것을k
먼저 시도하여 프로세스 속도를 높이는 데 도움이 될 수 있습니다
- reluctant 수정자는
명령문 의 !
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,})\1+
소수가 아닌n
적절한 배수 인지 확인합니다.k >= 2
꺼리는 수정자를 ?
설정 한 것을 제외 하고 \1
(명확성을 위해 생략) 위의 정규식은 원본과 동일합니다.
더 재미있는 정규식
다음 정규식은 비슷한 기술을 사용합니다. 교육적이어야합니다.
System.out.println(
"OhMyGod=MyMyMyOhGodOhGodOhGod"
.replaceAll("^(.+)(.+)(.+)=(\\1|\\2|\\3)+$", "$1! $2! $3!")
); // prints "Oh! My! God!"
또한보십시오
답변
좋은 정규식 트릭 (매우 비효율적이지만) … 🙂
정규 표현식은 비 프라임을 다음과 같이 정의합니다.
N <= 1 OR N이 K> 1로 나눌 수있는 경우에만 N이 소수가 아닙니다.
N의 간단한 디지털 표현을 정규식 엔진에 전달하는 대신 반복 문자로 구성된 길이 N 의 시퀀스가 제공됩니다 . 분리의 첫 번째 부분은 N = 0 또는 N = 1을 확인하고 두 번째 부분은 역 참조를 사용하여 제수 K> 1을 찾습니다. 정규식 엔진이 시퀀스를 형성하기 위해 적어도 두 번 반복 될 수있는 비어 있지 않은 하위 시퀀스를 찾도록 강제합니다. 이러한 서브 시퀀스가 존재하면, 길이가 N을 나누므로 N이 소수가 아님을 의미합니다.