Tôi sẽ giải thích phần regex bên ngoài kiểm tra tính nguyên thủy: regex sau đây, được đưa ra String s
bao gồm lặp lại String t
, tìm thấy t
.
System.out.println(
"MamamiaMamamiaMamamia".replaceAll("^(.*)\\1+$", "$1")
); // prints "Mamamia"
Cách thức hoạt động của nó là regex thu hút (.*)
vào \1
, và sau đó xem nếu có \1+
theo dõi nó. Sử dụng ^
và $
đảm bảo rằng một trận đấu phải là của toàn bộ chuỗi.
Vì vậy, theo một cách nào đó, chúng ta được đưa ra String s
, đó là một "bội số" String t
và regex sẽ tìm thấy như vậy t
(lâu nhất có thể, vì \1
là tham lam).
Khi bạn hiểu lý do tại sao regex này hoạt động, sau đó (bỏ qua thay thế đầu tiên trong regex của OP bây giờ) giải thích cách nó được sử dụng để kiểm tra tính nguyên thủy là đơn giản.
- Để kiểm tra tính nguyên thủy của
n
, trước tiên hãy tạo một String
độ dài n
(chứa đầy char
)
- Regex thu được một
String
khoảng thời gian (nói k
) vào \1
và cố gắng khớp \1+
với phần còn lại củaString
- Nếu có một trận đấu, thì đó
n
là bội số thích hợp k
, và do đó n
không phải là số nguyên tố.
- Nếu không có kết quả trùng khớp, thì không
k
tồn tại sự phân chia như vậy n
, và n
do đó là một nguyên tố
Làm thế nào để .?|(..+?)\1+
khớp số nguyên tố?
Thật ra thì không! Nó phù hợp String
với độ dài của nó là KHÔNG nguyên tố!
.?
: Phần đầu tiên của các kết quả trùng khớp String
có độ dài 0
hoặc 1
(KHÔNG phải là số nguyên tố theo định nghĩa)
(..+?)\1+
: Phần thứ hai của sự xen kẽ, một biến thể của biểu thức chính được giải thích ở trên, khớp với String
độ dài n
là "bội số" của một String
độ dài k >= 2
(nghĩa n
là một hỗn hợp, KHÔNG phải là số nguyên tố).
- Lưu ý rằng công cụ sửa đổi miễn cưỡng
?
thực sự không cần thiết cho tính chính xác, nhưng nó có thể giúp tăng tốc quá trình bằng cách thử nhỏ hơn k
trước
Lưu ý !
boolean
toán tử bổ sung trong return
câu lệnh: nó phủ định matches
. Đó là khi regex KHÔNG khớp, n
là chính! Đó là logic hai mặt tiêu cực, vì vậy không có gì lạ khi nó khó hiểu !!
Đơn giản hóa
Đây là cách viết lại mã đơn giản để dễ đọc hơn:
public static boolean isPrime(int n) {
String lengthN = new String(new char[n]);
boolean isNotPrimeN = lengthN.matches(".?|(..+?)\\1+");
return !isNotPrimeN;
}
Ở trên về cơ bản giống như mã Java ban đầu, nhưng được chia thành nhiều câu lệnh với các phép gán cho các biến cục bộ để làm cho logic dễ hiểu hơn.
Chúng ta cũng có thể đơn giản hóa regex, sử dụng sự lặp lại hữu hạn, như sau:
boolean isNotPrimeN = lengthN.matches(".{0,1}|(.{2,})\\1+");
Một lần nữa, đưa ra một String
chiều dài n
, chứa đầy char
,
.{0,1}
kiểm tra nếu n = 0,1
, KHÔNG nguyên tố
(.{2,})\1+
kiểm tra nếu n
là bội số thích hợp của k >= 2
, KHÔNG phải là số nguyên tố
Ngoại trừ công cụ sửa đổi miễn cưỡng ?
trên \1
(được bỏ qua cho rõ ràng), regex ở trên giống hệt với bản gốc.
Regex vui hơn
Regex sau đây sử dụng kỹ thuật tương tự; nó nên mang tính giáo dục:
System.out.println(
"OhMyGod=MyMyMyOhGodOhGodOhGod"
.replaceAll("^(.+)(.+)(.+)=(\\1|\\2|\\3)+$", "$1! $2! $3!")
); // prints "Oh! My! God!"
Xem thêm
!new String(new char[n]).matches(".?|(..+?)\\1+")
tương đương với!((new String(new char[n])).matches(".?|(..+?)\\1+"))
.