[java] 숫자가 정규 표현식의 소수인지 확인하는 방법은 무엇입니까?

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먼저 시도하여 프로세스 속도를 높이는 데 도움이 될 수 있습니다

명령문 의 ! boolean보수 연산자에 유의하십시오 . 정규식이 일치 하지 않을 때가 가장 중요합니다! 이중 음의 논리이므로 혼란 스럽습니다.returnmatchesn


단순화

다음은 코드를보다 읽기 쉽게 작성하기 위해 다시 작성하는 것입니다.

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이 소수가 아님을 의미합니다.


답변

/^1?$|^(11+?)\1+$/

밑이 1로 변환 된 후 숫자에 적용됩니다 (1 = 1, 2 = 11, 3 = 111, …). 비 프라임은 이것과 일치합니다. 일치하지 않으면 프라임입니다.

여기에 설명 하십시오 .


답변