Düzenli ifade (normal ifade) nedir?
Aslında, bir düzenli ifade, metinde bir dize bulmak için kullanılan bir kalıptır. Java'da, bu kalıbın orijinal gösterimi her zaman bir dizgedir, yani sınıfın bir nesnesidirString
. Ancak, normal bir ifadede derlenebilen herhangi bir dize değildir; yalnızca düzenli ifadeler oluşturma kurallarına uyan dizelerdir. Sözdizimi, dil belirtiminde tanımlanır. Normal ifadeler, normal ifade sözdiziminde özel anlamı olan karakterler olan meta karakterlerin yanı sıra harfler ve sayılar kullanılarak yazılır. Örneğin:
String regex = "java"; // The pattern is "java";
String regex = "\\d{3}"; // The pattern is three digits;
Java'da düzenli ifadeler oluşturma
Java'da düzenli bir ifade oluşturmak iki basit adımı içerir:- normal ifade sözdizimine uyan bir dize olarak yazın;
- dizgiyi düzenli bir ifadede derleyin;
Pattern
nesne oluşturarak düzenli ifadelerle çalışmaya başlarız. Bunu yapmak için, sınıfın iki statik yönteminden birini çağırmamız gerekir: compile
. İlk yöntem bir bağımsız değişken (düzenli ifadeyi içeren bir dize hazır değeri) alırken, ikincisi kalıp eşleştirme ayarlarını belirleyen ek bir bağımsız değişken alır:
public static Pattern compile (String literal)
public static Pattern compile (String literal, int flags)
Parametrenin potansiyel değerlerinin listesi sınıfta flags
tanımlanır Pattern
ve bize statik sınıf değişkenleri olarak sunulur. Örneğin:
Pattern pattern = Pattern.compile("java", Pattern.CASE_INSENSITIVE); // Pattern-matching will be case insensitive.
Temel olarak Pattern
sınıf, düzenli ifadeler için bir kurucudur. Başlık altında, compile
yöntem, derlenmiş bir temsil oluşturmak için sınıfın özel kurucusunu çağırır Pattern
. Bu nesne yaratma mekanizması değişmez nesneler yaratmak için bu şekilde uygulanır. Normal bir ifade oluşturulduğunda sözdizimi kontrol edilir. Dize hatalar içeriyorsa, o zaman bir PatternSyntaxException
oluşturulur.
Normal ifade sözdizimi
<([{\^-=$!|]})?*+.>
Normal ifade sözdizimi , harflerle birleştirilebilen karakterlere dayanır . Rollerine bağlı olarak, birkaç gruba ayrılabilirler:
Meta karakter | Tanım |
---|---|
^ | bir satırın başlangıcı |
$ | bir satırın sonu |
\B | kelime sınırı |
\B | sözcük olmayan sınır |
\A | girişin başlangıcı |
\G | önceki maçın sonu |
\Z | girişin sonu |
\z | girişin sonu |
Meta karakter | Tanım |
---|---|
\D | hane |
\D | rakamsız |
\S | boşluk karakteri |
\S | boşluk olmayan karakter |
\w | alfasayısal karakter veya alt çizgi |
\W | harfler, sayılar ve alt çizgi dışında herhangi bir karakter |
. | herhangi bir karakter |
Meta karakter | Tanım |
---|---|
\T | sekme karakteri |
\N | yeni satır karakteri |
\R | satırbaşı |
\F | satır besleme karakteri |
\u0085 | sonraki satır karakteri |
\u2028 | satır ayırıcı |
\u2029 | paragraf ayırıcı |
Meta karakter | Tanım |
---|---|
[ABC] | listelenen karakterlerden herhangi biri (a, b veya c) |
[^abc] | listelenenler dışında herhangi bir karakter (a, b veya c değil) |
[a-zA-Z] | birleştirilmiş aralıklar (a'dan z'ye Latin karakterleri, büyük/küçük harf duyarlı değildir) |
[reklam[mp]] | karakter birliği (a'dan d'ye ve m'den p'ye) |
[az&&[tanım]] | karakterlerin kesişimi (d, e, f) |
[az&&[^bc]] | karakterlerin çıkarılması (a, dz) |
Meta karakter | Tanım |
---|---|
? | biri ya da hiçbiri |
* | sıfır veya daha fazla kez |
+ | bir veya daha fazla kez |
{N} | n kez |
{N,} | n veya daha fazla kez |
{n,m} | en az n kez ve en fazla m kez |
Açgözlü niceleyiciler
Nicelik belirteçleri hakkında bilmeniz gereken bir şey, bunların üç farklı çeşidi olduğudur: açgözlü, sahiplenici ve isteksiz.+
Niceleyiciden sonra bir " " karakteri ekleyerek bir niceleyiciyi iyelik haline getirirsiniz . " " ekleyerek isteksiz hale getiriyorsunuz ?
. Örneğin:
"A.+a" // greedy
"A.++a" // possessive
"A.+?a" // reluctant
Farklı niceleyici türlerinin nasıl çalıştığını anlamak için bu modeli kullanmayı deneyelim. Varsayılan olarak, niceleyiciler açgözlüdür. Bu, dizideki en uzun eşleşmeyi aradıkları anlamına gelir. Aşağıdaki kodu çalıştırırsak:
public static void main(String[] args) {
String text = "Fred Anna Alexander";
Pattern pattern = Pattern.compile("A.+a");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
System.out.println(text.substring(matcher.start(), matcher.end()));
}
}
şu çıktıyı alıyoruz:
Anna Alexa
" " normal ifadesi için A.+a
kalıp eşleştirme şu şekilde gerçekleştirilir:
-
Belirtilen kalıptaki ilk karakter Latin harfidir
A
.Matcher
sıfır dizininden başlayarak metnin her karakteriyle karşılaştırır. Karakter,F
metnimizde sıfır dizinindedir, bu nedenle,Matcher
kalıpla eşleşene kadar karakterler arasında yinelenir. Örneğimizde, bu karakter 5. indekste bulunur. -
Modelin ilk karakteri ile bir eşleşme bulunduğunda,
Matcher
ikinci karakteri ile bir eşleşme arar. Bizim durumumuzda,.
herhangi bir karakteri temsil eden " " karakteridir.Karakter
n
altıncı konumdadır. Kesinlikle "herhangi bir karakter" için bir eşleşme olarak nitelendirilir. -
Matcher
desenin bir sonraki karakterini kontrol etmeye devam eder. Bizim kalıbımızda, önceki karaktere uygulanan niceleyiciye dahil edilmiştir: ".+
". Örüntümüzdeki "herhangi bir karakter"in tekrar sayısı bir veya daha fazla olduğu için,Matcher
art arda diziden bir sonraki karakteri alır ve "herhangi bir karakter" ile eşleştiği sürece kalıpla karşılaştırır. Örneğimizde — dizenin sonuna kadar (7. dizinden 18. dizine).Temel olarak,
Matcher
ipi sonuna kadar yutar - "açgözlü" ile kastedilen tam olarak budur. -
Matcher metnin sonuna ulaştıktan ve
A.+
kalıbın " " kısmı için kontrolü bitirdikten sonra, kalıbın geri kalanını kontrol etmeye başlar:a
. İleriye giden başka metin yok, bu nedenle kontrol, son karakterden başlayarak "geri çekilerek" devam ediyor: -
Matcher
.+
kalıbın " " kısmındaki tekrar sayısını "hatırlar" . Bu noktada, tekrar sayısını bir azaltır ve bir eşleşme bulunana kadar daha büyük kalıbı metne göre kontrol eder:
İyelik niceleyicileri
İyelik niceleyicileri, açgözlü niceleyicilere çok benzer. Aradaki fark, metin dizenin sonuna kadar yakalandığında, "geri çekilirken" kalıp eşleştirme olmamasıdır. Başka bir deyişle, ilk üç aşama açgözlü niceleyicilerle aynıdır. Dizinin tamamını yakaladıktan sonra eşleştirici, desenin geri kalanını düşündüğü şeye ekler ve onu yakalanan diziyle karşılaştırır. Örneğimizde, "A.++a
" normal ifadesini kullanan ana yöntem hiçbir eşleşme bulamıyor.
isteksiz niceleyiciler
-
Açgözlü çeşitlilikte olduğu gibi, bu niceleyiciler için kod, modelin ilk karakterine dayalı bir eşleşme arar:
-
Ardından, kalıbın bir sonraki karakteriyle (herhangi bir karakter) bir eşleşme arar:
-
Açgözlü kalıp eşleştirmenin aksine, gönülsüz kalıp eşleştirmede en kısa eşleşme aranır. Bu, kalıbın ikinci karakteriyle (metindeki 6. konumdaki karaktere karşılık gelen bir nokta) bir eşleşme bulduktan sonra,
Matcher
metnin kalıbın geri kalanıyla - "a
" karakteriyle eşleşip eşleşmediğini kontrol ettiği anlamına gelir. -
Metin kalıpla eşleşmiyor (yani
n
7. indekste " " karakterini içeriyor), bu nedenleMatcher
nicelik belirteci bir veya daha fazlasını gösterdiği için birden fazla "herhangi bir karakter" ekler. Ardından, deseni 5'ten 8'e kadar olan konumlardaki metinle tekrar karşılaştırır:
Bizim durumumuzda bir eşleşme bulundu, ancak henüz metnin sonuna gelmedik. Bu nedenle örüntü eşleştirme 9. konumdan yeniden başlar, yani örüntünün ilk karakteri benzer bir algoritma kullanılarak aranır ve bu, metnin sonuna kadar tekrarlanır.
main
" " kalıbını kullanırken aşağıdaki sonucu elde eder A.+?a
: Anna Alexa Örneğimizden de görebileceğiniz gibi, farklı tip niceleyiciler aynı kalıp için farklı sonuçlar üretir. Bu yüzden bunu aklınızda bulundurun ve aradığınız şeye göre doğru çeşidi seçin.
Normal ifadelerde kaçan karakterler
Java'daki bir düzenli ifade veya daha doğrusu orijinal gösterimi bir dizge değişmez değeri olduğundan, dize değişmezleriyle ilgili Java kurallarını hesaba katmamız gerekir. Özellikle,\
Java kaynak kodundaki dizge değişmezlerindeki " " ters eğik çizgi karakteri, derleyiciye bir sonraki karakterin özel olduğunu ve özel bir şekilde yorumlanması gerektiğini söyleyen bir kontrol karakteri olarak yorumlanır. Örneğin:
String s = "The root directory is \nWindows"; // Move "Windows" to a new line
String s = "The root directory is \u00A7Windows"; // Insert a paragraph symbol before "Windows"
Bu, normal ifadeleri tanımlayan ve " \
" karakterlerini (yani metakarakterleri belirtmek için) kullanan dize hazır değerlerinin, Java bayt kodu derleyicisinin dizeyi yanlış yorumlamamasını sağlamak için ters eğik çizgileri tekrar etmesi gerektiği anlamına gelir. Örneğin:
String regex = "\\s"; // Pattern for matching a whitespace character
String regex = "\"Windows\""; // Pattern for matching "Windows"
"Normal" karakterler olarak kullanmak istediğimiz özel karakterlerden kaçmak için çift ters eğik çizgi de kullanılmalıdır. Örneğin:
String regex = "How\\?"; // Pattern for matching "How?"
Pattern sınıfının yöntemleri
SınıfınPattern
normal ifadelerle çalışmak için başka yöntemleri vardır:
-
String pattern()
‒ nesneyi oluşturmak için kullanılan normal ifadenin orijinal dize gösterimini döndürürPattern
:Pattern pattern = Pattern.compile("abc"); System.out.println(pattern.pattern()); // "abc"
-
static boolean matches(String regex, CharSequence input)
– normal ifade olarak iletilen normal ifadeyi, olarak iletilen metne karşı kontrol etmenizi sağlarinput
. İadeler:true - metin kalıpla eşleşirse;
false - değilse;Örneğin:
System.out.println(Pattern.matches("A.+a","Anna")); // true System.out.println(Pattern.matches("A.+a","Fred Anna Alexander")); // false
-
int flags()
‒ model oluşturulduğunda modelinflags
parametre seti değerini veya parametre ayarlanmamışsa 0 değerini döndürür. Örneğin:Pattern pattern = Pattern.compile("abc"); System.out.println(pattern.flags()); // 0 Pattern pattern = Pattern.compile("abc",Pattern.CASE_INSENSITIVE); System.out.println(pattern.flags()); // 2
-
String[] split(CharSequence text, int limit)
– geçirilen metni bir diziye bölerString
. Parametrelimit
, metinde aranan maksimum eşleşme sayısını gösterir:- eğer
limit > 0
‒limit-1
eşleşirse; - eğer
limit < 0
- metindeki tüm eşleşmeler - eğer
limit = 0
‒ metindeki tüm eşleşmeler, dizinin sonundaki boş dizeler atılırsa;
Örneğin:
public static void main(String[] args) { String text = "Fred Anna Alexa"; Pattern pattern = Pattern.compile("\\s"); String[] strings = pattern.split(text,2); for (String s : strings) { System.out.println(s); } System.out.println("---------"); String[] strings1 = pattern.split(text); for (String s : strings1) { System.out.println(s); } }
Konsol çıktısı:
Fred Anna Alexa --------- Fred Anna Alexa
Aşağıda, sınıfın bir
Matcher
nesne oluşturmak için kullanılan başka bir yöntemini ele alacağız. - eğer
Matcher sınıfının yöntemleri
Sınıfın örnekleri,Matcher
desen eşleştirmeyi gerçekleştirmek için oluşturulur. Matcher
düzenli ifadeler için "arama motorudur". Bir arama yapmak için ona iki şey vermemiz gerekir: bir model ve bir başlangıç dizini. Matcher
Bir nesne yaratmak için , Pattern
sınıf aşağıdaki yöntemi sağlar: рublic Matcher matcher(CharSequence input)
Yöntem, aranacak olan bir karakter dizisini alır. Bu, arabirimi uygulayan bir sınıfın örneğidir CharSequence
. String
Yalnızca a'yı değil , aynı zamanda StringBuffer
, StringBuilder
, Segment
veya'yı da iletebilirsiniz CharBuffer
. Desen, yöntemin çağrıldığı bir Pattern
nesnedir matcher
. Eşleştirici oluşturma örneği:
Pattern p = Pattern.compile("a*b"); // Create a compiled representation of the regular expression
Matcher m = p.matcher("aaaaab"); // Create a "search engine" to search the text "aaaaab" for the pattern "a*b"
Artık eşleşmeleri aramak, metindeki bir eşleşmenin konumunu almak ve sınıfın yöntemlerini kullanarak metni değiştirmek için "arama motorumuzu" kullanabiliriz. Yöntem boolean find()
, metindeki bir sonraki eşleşmeyi arar. Metnin tamamını bir olay modelinin parçası olarak analiz etmek için bu yöntemi ve bir döngü deyimini kullanabiliriz. Yani bir olay meydana geldiğinde yani metinde bir eşleşme bulduğumuzda gerekli işlemleri yapabiliyoruz. Örneğin, bir eşleşmenin metindeki konumunu belirlemek için bu sınıfın int start()
ve yöntemlerini kullanabiliriz . Eşleşmeleri değiştirme parametresinin değeriyle değiştirmek için ve yöntemlerini int end()
kullanabiliriz . Örneğin: String replaceFirst(String replacement)
String replaceAll(String replacement)
public static void main(String[] args) {
String text = "Fred Anna Alexa";
Pattern pattern = Pattern.compile("A.+?a");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
int start=matcher.start();
int end=matcher.end();
System.out.println("Match found: " + text.substring(start, end) + " from index "+ start + " through " + (end-1));
}
System.out.println(matcher.replaceFirst("Ira"));
System.out.println(matcher.replaceAll("Mary"));
System.out.println(text);
}
Çıktı:
Match found: Anna from index 5 through 8
Match found: Alexa from index 10 through 14
Fred Ira Alexa
Fred Mary Mary
Fred Anna Alexa
Örnek, replaceFirst
ve replaceAll
yöntemlerinin yeni bir String
nesne - orijinal metindeki kalıp eşleşmelerinin, yönteme bağımsız değişken olarak iletilen metinle değiştirildiği bir dize - yarattığını açıkça ortaya koymaktadır. Ayrıca, replaceFirst
yöntem yalnızca ilk eşleşmeyi değiştirir, ancak replaceAll
yöntem metindeki tüm eşleşmeleri değiştirir. Orijinal metin değişmeden kalır. ve sınıflarının en sık düzenli ifade işlemleri doğrudan sınıfın içine yerleştirilmiştir Pattern
. Bunlar , , ve gibi yöntemlerdir . Ancak, bu yöntemler, gizli olarak ve sınıflarını kullanır. Bu nedenle, herhangi bir ekstra kod yazmadan bir programdaki metni değiştirmek veya dizeleri karşılaştırmak istiyorsanız, aşağıdaki yöntemleri kullanın:Matcher
String
split
matches
replaceFirst
replaceAll
Pattern
Matcher
String
sınıf. Daha gelişmiş özelliklere ihtiyacınız varsa, Pattern
ve Matcher
sınıflarını unutmayın.
Çözüm
Bir Java programında, düzenli bir ifade, belirli kalıp eşleştirme kurallarına uyan bir dize tarafından tanımlanır. Kod yürütülürken, Java makinesi bu diziyi bir nesnede derlerPattern
ve Matcher
metindeki eşleşmeleri bulmak için bir nesne kullanır. Başta da söylediğim gibi, insanlar genellikle normal ifadeleri zor bir konu olarak gördükleri için sonraya erteliyorlar. Ancak temel sözdizimini, meta karakterleri ve karakter kaçışını anlarsanız ve normal ifadelerin örneklerini incelerseniz, bunların ilk bakışta göründüklerinden çok daha basit olduğunu göreceksiniz.
Daha fazla okuma: |
---|
GO TO FULL VERSION