Bu konu bir blog yazısında anlatılacak kadar kısa bir konu değil; farkındayım. Ama konunun ana hatlarını yine de özetlemek istiyorum.
Bir metnin içinde (düzyazı, program, bir klasördeki dosya içerikleri, URL dizileri, dosys sistemi yolları vs) bir "dünya" var mı yok mu aramak istiyoruz. Örneğin bir klasördeki txt uzantılı dosyaların içinde. Bunu powershell ile yapmanın yolu
> Select-String -Pattern "dünya" -Path *.txt
Bu arama bize bazı sonuçlar döner. Ama diyelim ki dosyaların bazılarında "ü" yerine "u" kullanıldığını farkettik. Bu durumda "dunya" anahtar kelimesini de içerecek şekilde aramamızı değiştirelim. Ayrıca varsayılan parametre sıralaması ve alias kullanımıyla komutu biraz kısalatalım.
> sls "dünya|dunya" *.txt
"|" operatörü VEYA işlemi görür. Burada değişen 1 harf olduğu için bunu ü VEYA u şeklinde de yapabilirdik.
> sls "d[u|ü]nya" *.txt
Köşeli parantezler, bir karakter kümesi belirtmek için kullanılır. Örneğin sadece d,u,ü,n,y ve a'dan oluşan 5 veya 6 harfli kelimeleri bulmak istersek
> sls "[adnuüy]{5,6}" *.txt
yazabiliriz. Bu satırla sadece dünya ve dunya anahtar kelimelerini bulmakla kalmayacağız, ayrıca içinde herhangi bir sırada bu harflerin 5 veya 6'sı geçen başka kelimeleri de bulacağız. Ayrıca bunlar tam kelimeler de olmayacak, kelimenin herhangi bir bölümünde bu harflerin 5 veya 6'sının geçmesi yeterli olacak.
Bazı özel operatörleri listeleyelim:
? | Önceki karakter 0 veya 1 kez geçecek |
* | Önceki karakter 0 veya daha fazla
geçecek. |
+ | Önceki karakter 1 veya daha fazla geçecek. |
{n,} | Önceki karakter n veya daha fazla
geçecek. |
{n,m} | Önceki karakter en az n kere, en fazla m kere geçecek. Arasındaki sayılarda da olabilir. |
. |
Yeni satır karakteri hariç her tekil karakteri bulur. |
[a-z] | Yalnızca "a" ve "z" arazındaki karakterleri
bulur. |
[^abc] | a, b ve c olmayan her karakteri bulur. |
^ | Satırın başını bulur. |
$ | Satırın sonunu
bulur. |
( ) | Gruplandırma için. Parantezin içindeki ifade hatırlanır ve daha sonra \n veya $n gibi bir operatör
ile kullanılabilir. |
(?:) | Aynen ( ) gibi gruplandırma için kullanılır, ama parantezin içindeki ifade
hatırlanmaz |
| | veya operatörü |
\w | tüm harfleri bulur. |
\W | harf olmayan karakterleri bulur. |
\s | Boşluk karakterlerini bulur. |
\S | Boşluk olmayan karakterleri bulur. |
\d | Sayıları bulur. |
\D | Sayı
olmayanları bulur. |
\A | String'in başını bulur. |
\Z | String'in sonunu bulur. Bir yeni satır karakteri varsa
ondan hemen öncesini bulur. |
\z | String'in sonunu bulur.Yeni satır karakterini de atlar. |
\G | En son aramanın
bulduğu noktanın bir sonrasını bulur. |
\b | Kelime sınırlarını bulur. |
\B | Kelime olmayan sınırları bulur\. |
Bir string değişkenimiz olsun, aşağıdaki gibi
> $str1 = "Bugün günlerden Pazartesi"
Regular expression ifadelerimizin nasıl çalıştığını bu string üzerinde deneyerek görelim. Powershell'de -match operatörü regular expression kullanır. Ama -like kullanmaz. Değiştirme operatörü -replace de regular expression kullanır. Değişkenin içinde "gün" geçiyor mu bakalım:
> $str1 -match "gun"
False
Sonuç altta "False" olarak verildi. "u" ve "ü" alternatifli olarak deneyelim:
> $str1 -match "g[u|ü]n"
True
Bu şekilde bir eşleşme bulundu. Pazartesi geçen kelimeleri Salı ile değiştirmek için
> $str1 -replace "Pazartesi","Salı"
Bugün günlerden Salı
Çok karşılaşılabilecek bir şey, ay\gün\yıl şeklinde yazılan tarihlerin gün.ay.yıl şeklinde çevrilmesi olabilir. Bunun için back reference denen gruplandırma operatörü olarak yukarıdaki tabloda listelediğim parantezleri kullanmalıyız. İşlem şu şekilde olacak, 2 haneli ay bilgisi bulunacak, 2 haneli gün bilgisi bulunacak, bunlar yer değiştirilecek ve ayraç olarak kullanılan "\" yerine "." konacak ve sonrasında gelen 4 haneli yıl bilgisi değiştirilmeyecek. Bunun için bulduğu gün, ay ve yıl verilerini hatırlaması gerekecek.
> $str1 = "bugün 11\20\1974"
> $str1 -replace '(\d{2})\\(\d{2})\\(\d{4})','$2.$1.$3'
bugün 20.11.1974
Burada çift tırnak yerine tek tırnak kullanmaya dikkat.
Çok sık yaşadığım bir konu, bir klasörde bir dosya arıyorum. Dosya adında geçen bir anahtar kelimeye göre aramak kolay. Ama 2 anahtar kelimem var ve hangisi önce gelecek, hangisi sonra gelecek, aralarında başka kelime olacak mı, bu ayrıntılar önemli değil. Sadece bu 2 anahtar kelimenin dosya adında geçmesini istiyorum. Bunun için yapılması gereken [3]:
> dir * | where {$_.Name -match "(?=.*format)(?=.*powershell)"}
Benzer şekilde bir klasördeki dosyaların içinde de geçmesini istediğim 2 anahtar kelime için arama yapabilirim [9]:
> sls "(?=.*black)(?=.*star)" *-d.txt
Ekleme 2022-07-13: linux komut satırı aracı grep'in alışkanlıkları biraz farklı. farketebildiğim istisnaları şöyle:
\d -> [[:digit:]]
\w -> [[:blank:]]
ayrıca [8]'de anlatıldığı gibi şu "karakter sınıfları" da var:
[[:alpha:]] Alfabetik karakterler
[[:alphanum:]] Alfanumberik karakterler
[[:lower:]] küçük harfler
[[:upper:]] büyük harfler
Bunlara "genişletilmiş düzenli ifadeler" (extended regular expressions) denmiş. Bunları kullanmak için grep'e -E anahtarını sağlamamız istenmiş. Örneğin Manjaro'da linux çekirdeği kurulma tarihlerini /var/log/pacman.log dosyasından süzmek için
> grep -E "installed linux[[:digit:]]{2,3}[[:blank:]]" /var/log/pacman.log
kullandım. Her yeni çekirdek kurulumunda installed linux, güncellemesinde ise upgraded linux, sonrasında ise duruma göre 2 veya 3 karakterlik sürüm numarasını yazıyordu. Yeni çekirden yardımcı paketlerle geldiğinden bir tire karakteriyle bu yardımcı karekterler de listelenmesin diye [[:blank:]] de kullandım.
Ek 2023-06-04: Bazen de grep ile "içine geçmeyen"leri bulmak gerekir. Bu durum için grep için -v anahtarı önerilmiş. Şöyle olabilir:
> grep "icinde_gesin" /var/log/birdosya | grep -v "gecmesin"
Ek 2023-10-17: İçinde IP adresi olan bir string değişkenimiz var. Bu string'in içinde geçen IP adresini görmek istiyoruz. Yöntemlerden biri:
PS> ($metin | select-string -Pattern "([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})").Matches[0].Value
diğeri de
PS> $metin -match "([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})"
PS> $matches[0]
---
[1] https://en.wikipedia.org/wiki/Regular_expression
[2] https://regexr.com/
[3] https://www.baeldung.com/string-contains-multiple-words
[4] https://www.regular-expressions.info/
[5] https://www3.ntu.edu.sg/home/ehchua/programming/howto/Regexe.html
[6] https://regex101.com/
[7] https://www.geeksforgeeks.org/write-regular-expressions/
[8] https://linuxize.com/post/regular-expressions-in-grep/
[9] https://www.rexegg.com/regex-lookarounds.html