Wyrażenie regularne sprawdzające, czy liczba jest pierwsza

Wyrażenie regularne, które potrafi sprawdzić, czy dana liczba jest pierwsza.

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

import static java.lang.System.*;

public class Prime {

	public static final String PRIME_REGEX = "^1?$|^(11+?)\\1+$";

	public static boolean isPrime(int i) {
		String s = "";
		while (i > 0) {
			i--;
			s += "1";
		}
		return !Pattern.matches(PRIME_REGEX, s); // escape the \1
	}

	public static void main(String[] args) {

		final int i = Integer.parseInt(args[0]);
		final boolean isPrime = isPrime(i);
		out.println(i + " is" + (isPrime ? "" : " not") + " a prime number");
	}
}
<barista@javaczyherbata.pl> java Prime 9
9 is not a prime number

Jak to działa?

Aby sprawdzić, czy dana liczba jest pierwsza, zapisuje się ją jako ciąg n jedynek, gdzie n równa się jej samej. Np. 5 reprezentowane jest przez ciąg „11111”.

Wyrażenie składa się z dwóch części oddzielonych „|” (or). Jeśli ciąg zostanie dopasowany, dana liczba nie jest pierwsza; w przeciwnym wypadku – jest.

Pierwsza część (^1?$) dopasowuje początek linii (^), zero lub jedną „1” (1?) oraz koniec linii.
Zatem dopasuje się do ciągów „” oraz „1” oznaczających kolejno cyfry 0 oraz 1. Jak wiemy 0 i 1 nie są liczbami pierwszymi.

Druga część wyrażenia (^(11+?)\1+$) jest bardziej skomplikowana. Dopasowuje początek linii (^), następnie jeden znak „1” oraz jeden lub więcej znaków „1” (11+?). To co zostało dopasowane, trafia w miejsce (\1) i jest dopasowywane jeden lub więcej razy (zachłannie). Następnie dopasowywany jest koniec linii. Ze względu na (zachłanny) znak „+” w \1+, jeśli nie powiedzie się dopasowanie z maksymalną ilością powtórzeń, nastąpi próba dopasowania z mniejszą ilością powtórzeń. Natomiast ze względu na (niezachłanny) znak „?” w 11+?, jeśli minimalny ciąg nie zostanie dopasowany, następuje próba dopasowania ciągu dłuższego o jeden znak.

Najlepiej obrazuje to przykład. Rozważmy cyfrę 9.

  1  1  1  1  1  1  1  1  1    ^(11+?) dopasowuje dwie jedynki "11" na początku 
^ (\1)                         i zapisuje je w \1

  1  1  1  1  1  1  1  1  1    następnie dopasowuje jeden lub więcej ciągów z \1,
^ (\1)  [  ]  [  ]  [  ]  $    ale dopasowanie się nie powodzi - to nie koniec ciągu

  1  1  1  1  1  1  1  1  1    dopasowanie mniejszej ilości powtórzeń \1 także się    
^ (\1)  [  ]  [  ]             nie powodzi

  1  1  1  1  1  1  1  1  1    dopasowanie jeszcze mniejszej ilości powtórzeń \1    
^ (\1)  [  ]                   także się nie powodzi

  1  1  1  1  1  1  1  1  1    ^(11+?) dopasowuje trzy jedynki "111" na początku
^ ( \1  )                      i zapisuje je w \1

  1  1  1  1  1  1  1  1  1        
^ ( \1  )  [     ]  [     ] $  dopasowuje kolejne dwa wystąpienia "111"; PASUJE

Zatem cyfra 9 nie jest liczbą pierwszą.

Leave a Reply