Normal İfadeleri Ne Zaman Kullanmamalısınız? [kapalı]


50

Düzenli ifadeler, programcının cephaneliğinde güçlü bir araçtır, ancak - en iyi seçenek olmadığı ve hatta tamamen zararlı olduğu durumlarda bazı durumlar vardır.

Basit örnek # 1, HTML'yi regexp ile ayrıştırıyor - birçok hataya bilinen bir yol. Muhtemelen, bu aynı zamanda genel olarak ayrıştırmaya da atfedilir .

Ancak, düzenli ifadeler için açıkça görülmeyen alanlar var mı?


ps: " İstediğiniz soru sübjektif görünüyor ve kapatılması muhtemel. " - bu nedenle, regexps kullanımının sorunlara neden olduğu bilinen örneklerle ilgilendiğimi vurgulamak istiyorum.


9
Regexp ile HTML ayrıştırma sadece "sayısız hataya bilinen bir yol" değildir. Bu aslında imkansız .
Kramii, Monica

19
Sadece imkansız değil, aynı zamanda deliliğe ve ebedi lanetlenmeye
Martin Wickman

3
@ Jörg: Regexp sadece normal ifadelerin kısaltmasıdır.
Joren

3
@ Jörg: Matematikteki düzenli ifadeler ile yazılım kütüphanesindeki uygulamaları arasında büyük bir fark olduğu çok doğru. Ayrıca, düzenli ifade kütüphanelerinin çoğunun, onları yalnızca normal dilleri kabul etmekten çok daha uzağa yerleştiren uzantıları olduğu ve bunları düzenli ifade olarak adlandırmanın her zaman bu kadar uygun olmadığı da doğrudur. İki farklı kavramın olduğuna katılıyorum. Fakat aynı isme sahipler; regexp hala bir kısaltmadır, kendi içinde bir terim değildir. Bu örneklerin çoğunda bu sitede yazılım kütüphaneleri için tam terimin kullanılması.
Joren

2
@ Jörg - bunlar anlambilimdir. Bu kalıpları farklı isimlerle çağırmak iyi bir fikir olsa da (sadece "normal ifadeler normal diller için" yanlışlıktan kaçınmak için), "regexp" / "normal ifadeler" çok iyi bir girişim değildir ve sadece ek karışıklık.
Kobi

Yanıtlar:


60

Normal ifadeler kullanmayın:

  • Parsers olduğunda.

Bu HTML ile sınırlı değil . Basit bir geçerli XML, şemayı bilseniz ve asla değişmeyeceğini bilseniz bile, düzenli bir ifadeyle makul bir şekilde ayrıştırılamaz.

Örneğin, C # kaynak kodunu ayrıştırmaya çalışmayın . Bunun yerine, anlamlı bir ağaç yapısı veya belirteçleri elde etmek için ayrıştırın.

  • Daha genel olarak, işinizi yapacak daha iyi araçlara sahip olduğunuzda.

Hem küçük hem de büyük harfleri aramanız gerekiyorsa? Düzenli ifadeleri seviyorsanız, onları kullanacaksınız. Ancak iki aramayı birbiri ardına kullanmak daha kolay / daha hızlı / okunabilir değil mi? Şansların çoğu dildedir, daha iyi performans elde edersiniz ve kodunuzu daha okunaklı hale getirir.

Örneğin, Ingo'nun cevabındaki örnek kod, normal ifadeler kullanmamanız gerektiğinde iyi bir örnektir. Sadece ara foo, sonra ara bar.

  • İnsan yazısını ayrıştırırken.

Bunun iyi bir örneği müstehcenlik filtresidir. Sadece uygulamak genel olarak kötü bir fikir değil, aynı zamanda düzenli ifadeler kullanarak yapmak için cazip olabilirsiniz ve yanlış yaparsınız. Bir insanın bir kelime, sayı, cümle yazabileceği ve başka bir insan tarafından anlaşılacağı, ancak sizin düzenli ifadenizin pek çok yolu vardır. Bu yüzden gerçek bir müstehcenliği yakalamak yerine, düzenli ifadeniz zamanını diğer kullanıcıları incitmek için harcayacaktır.

  • Bazı veri türlerini doğrularken.

Örneğin, düzenli bir ifade ile bir e-posta adresini doğrulamayın. Çoğu durumda yanlış yaparsınız. Nadir bir durumda, doğru yapacaksınız ve 6 343 karakterlik kodlama korkusu ile bitireceksiniz .

Doğru araçlar olmadan, hata yaparsınız. Ve onları son anda, belki de asla görmeyeceksiniz. Temiz kod umursamıyorsanız, yorumsuz, boşluksuz, yeni satırsız bir yirmi satır dizisi yazacaksınız.

  • Kodunuz ne zaman okunacak. Ve sonra farklı geliştiriciler tarafından her seferinde tekrar tekrar, tekrar tekrar okuyun.

Cidden, eğer kodunuzu alırsam ve onu gözden geçirmeli ya da değiştirmeliysem, yirmi satır uzunluğundaki bir dizi sembolü anlamaya çalışmakla bir hafta geçirmek istemiyorum.


9
“Cidden, eğer kodunu alırsam ve onu gözden geçirir ya da değiştirirsem, bir haftayı yirmi satır uzunluğundaki birçok sembolü anlamaya çalışarak geçirmek istemiyorum.” 1!
funkybro

1
Bu, yığın taşması konusundaki üvey kız kardeşinden çok daha iyi bir cevaptır: stackoverflow.com/questions/7553722/…
Kobi

1
Eğer Perl / PCRE kullanıyorsanız (ve muhtemelen diğer modern regex lezzetlerini de kullanabilirsiniz), alt gruplara, yakalama gruplarına ve (?(DEFINE))iddialarına dikkat edin;) Bunları kullanarak çok temiz regex'ler yazabilirsiniz. yacc ya da benzerlerine yazacağınıza benzer şekilde;)
NikiC

2
Kara listeye alınan sözcükleri ayrıştırmak için normal ifadeler kullanmak clbuttic bir hatadır.
Dan Ray

Dünyada bir ipte regex atmaktan kaçınmak için hiçbir sebep yoktur "<a href='foo'>stuff</a>". Modern regex'lerin bu konuda bir sorunu yok.
tristrist

18

En önemli şey: ayrıştırdığınız dil normal bir dil olmadığında .

HTML değil normal bir dil ve bir düzenli ifade ile ayrıştırma olduğu değil (zor veya hatalı koduna bir yol sadece) mümkün.


4
Yanlış! Modern regex lezzetlerinden herhangi birini kullanıyorsanız (Perl, PCRE, Java, .NET, ...) özyineleme ve iddialar yapabilir ve böylece bağlamsız ve içeriğe duyarlı dilbilgileriyle eşleşebilir.
NikiC

9
@NikiC. Yanlış değil. "Modern regex lezzetleri" normal ifadeler değildir (normal dilleri, dolayısıyla adı ayrıştırmak için kullanılabilir). PRE ile daha fazlasını yapabileceğinizi kabul ediyorum, ancak ben sadece "normal ifadeler" olarak adlandırdım (orijinal sorudaki gibi).
Matteo,

1
Modern regex'ler, büyükannenizin öğrettiği şeylerin çok ötesinde, regexes'in tavsiyesinin önemsiz olduğunu yapabilir. İlkel regex'ler bile çoğu küçük HTML kod parçasını işleyebilir. Bu battaniye yasağı saçma ve gerçekçi değil. Regexes edildi yapılmış bu tür bir şey için. Ve evet, neden bahsettiğimi biliyorum .
tristrist

12

Biri sık sık görür StackOverflow'daki insanlar belirli bir dize gelmez öğrenmek regexes için sormak değil şu ya da bu içerirler. Bu, IMHO, düzenli ifadenin amacını tersine çeviriyor. Bir çözüm bulunsa bile (olumsuz bakış açıları ya da benzeri şeyler kullanılsa bile), regex'in ne için yapıldığını kullanmak ve programın mantığı ile olumsuz durumu ele almak genellikle çok daha iyidir.

Örnek:

# bad
if (/complicated regex that assures the string does NOT conatin foo|bar/) {
    # do something
}

# appropriate
if (/foo|bar/) {
    # error handling
} else {
    # do something
}

1
+1: Birkaç kez durup kendime "Tamam, özellikle neyi eşleştirmeye çalışıyorum?" "Ne kaçınmaya çalışıyorum?"

5

İki dava:

Daha kolay bir yol olduğunda

  • Dillerin çoğu, bir dize diğeri alt kümesi olup olmadığını belirlemek için INSTR gibi basit bir işlev sağlar. Yapmak istediğiniz şey buysa, basit işlevi kullanın. Kendi normal ifadenizi yazmayın.

  • Karmaşık bir dize işleme gerçekleştirmek için kullanılabilir bir kitaplık varsa, kendi normal ifadenizi yazmak yerine kullanın.

Düzenli ifadeler yeterince güçlü olmadığında

  • Bir ayrıştırıcıya ihtiyacınız varsa bir ayrıştırıcı kullanın.

0

Düzenli ifadeler özyinelemeli yapıları tanımlayamaz . Bu temel sınırlamadır.

JSON'u alın - oldukça basit bir formattır, ancak bir nesne üye değerler olarak diğer nesneleri içerebildiği için (keyfi olarak derin), sözdizimi özyinelemelidir ve regex tarafından ayrıştırılamaz. Öte yandan , özyinelemeli yapılar içermediğinden CSV regex'lerle ayrıştırılabilir.

Kısacası, düzenli ifadeler, kalıbın kendisine atıfta bulunmasına izin vermez. Söyleyemezsiniz: bu noktada sözdiziminde tüm kalıp tekrar eşleşir. Başka bir ifadeyle, normal ifadeler yalnızca doğrusal olarak eşleşir, iç içe geçmiş bir desenin ne kadar derin olduğunu izlemesine izin verecek bir yığın içermez.

Biçimin aksi takdirde ne kadar karmaşık veya karmaşık olduğu ile ilgisi olmadığını unutmayın. S-ifadeleri gerçekten çok basit, ancak bir regex ile ayrıştırılamaz. Öte yandan, CSS2 oldukça karmaşık bir dildir, ancak özyinelemeli yapılar içermez ve bunun için bir regex ile ayrıştırılabilir. (Yinelemeli bir sözdizimine sahip olan CSS ifadeleri nedeniyle bu, CSS3 için doğru olmamasına rağmen.)

Bu nedenle, yalnızca regex kullanarak HTML'yi ayrıştırmanın çirkin veya karmaşık veya hataya eğilimli olması nedeniyle değildir. Bu sadece mümkün değil olmasıdır .

Özyinelemeli yapılar içeren bir formatı ayrıştırmanız gerekirse, özyinelemeli yapıların seviyesini takip etmek için en azından düzenli ifadelerin bir yığınla kullanılmasını sağlamalısınız. Bu genellikle bir ayrıştırıcının nasıl çalıştığıdır. Düzenli ifadeler "doğrusal" bölümleri tanımak için kullanılırken, regex dışındaki özel kod iç içe yapıların izini sürmek için kullanılır.

Genellikle bu şekilde ayrıştırma ayrı aşamalara ayrılır. Tokenizasyon, girdiyi kelimeler, noktalama işaretleri, parantezler vb. Gibi "belirteçler" dizisine ayırmak için normal ifadelerin kullanıldığı ilk aşamadır. Ayrıştırma, bu belirteçlerin hiyerarşik bir yapıya, bir sözdizimi ağacına ayrıştırıldığı bir sonraki aşamadır.

Bu nedenle, HTML veya C # 'nın normal ifadelerle ayrıştırılamadığını duyduğunuzda, normal ifadelerin hala ayrıştırıcıların önemli bir parçası olduğunu unutmayın. Böyle bir dili yalnızca normal ifadeler kullanarak ve yardımcı kod kullanmadan ayrıştıramazsınız .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.