Regex Golf için ipuçları


43

Dile özgü golf oynama ipuçlarına benzer: düzenli ifadeleri kısaltmak için genel püf noktaları nelerdir?

Golf konusunda üç regex kullanımı görebiliyorum: klasik regex golf ("burada eşleşmesi gereken bir liste var ve burada başarısız olması gereken bir liste"), hesaplama problemlerini çözmek için regex kullanarak ve düzenli ifadeleri kullanmak daha büyük golf kodu. Bunlardan herhangi birini veya tümünü içeren ipuçlarını göndermekten çekinmeyin. Eğer bahşişiniz bir veya daha fazla lezzetle sınırlıysa, lütfen bu lezzetleri en üstte belirtin.

Her zamanki gibi, lütfen cevap başına bir ipucuna (ya da çok yakından ilgili ipuçlarının ailesine) bağlı kalın, böylece en faydalı ipuçlarını oylama yoluyla üst sıralara çıkarabilirsiniz.


Güçlü kendini tanıma: Hangi regex kullanım kategorisi bu kategoriye giriyor? codegolf.stackexchange.com/a/37685/8048
Kyle Strand

@KyleStrand "daha büyük golf kodunun parçaları olarak kullanılan normal ifadeler."
Martin Ender

Yanıtlar:


24

Kaçmamak için ne zaman

Bu kurallar, hepsi olmasa da çoğu lezzet için geçerlidir:

  • ] Eşleşmediğinde kaçmaya gerek yoktur.

  • {ve }bir tekrarlamanın parçası olmadıklarında kaçmaya gerek yoktur, örneğin tam anlamıyla {a}eşleşir {a}. Gibi bir şeyle eşleşmek isteseniz bile {2}, onlardan yalnızca kaçmanız gerekir, örneğin {2\}.

Karakter sınıflarında:

  • ]karakter kümesindeki ilk karakter olduğunda, örneğin []abc]bunlardan birini eşleştirdiğinde ]abcveya a'dan sonraki ikinci karakter olduğunda ^, örneğin [^]]hiçbir şeyle eşleşmeden kaçmaya gerek yoktur ]. (Önemli istisna: ECMAScript tadı!)

  • [kaçmaya hiç gerek yok. Yukarıdaki ipucu ile birlikte bu, her iki braketi korkunç karşı sezgisel karakter sınıfıyla eşleştirebileceğiniz anlamına gelir [][].

  • ^karakter kümesindeki ilk karakter olmadığında kaçmaya gerek yoktur , örneğin [ab^c].

  • -o da (ikinci bir sonraki ilk geldiğinde çıkış yapılmasını gerektirmez ^bir karakter kümesi, örneğin) veya son karakteri [-abc], [^-abc]ya [abc-].

  • Karakter sınıfının dışında meta karakter olsalar bile (ters eğik çizginin \kendisi hariç ) karakter sınıfının içinde başka hiçbir karakterin kaçması gerekmez .

Ayrıca, bazı tatlarda ^ve $sırasıyla regex'in başında veya sonunda olmadıklarında tam anlamıyla eşleşir.

(Birkaç ayrıntıyı doldurdukları için @ MartinBüttner'e teşekkürler)


Bazıları, gerçek noktadan kaçmayı, kaçmaya ihtiyaç duymadığı bir karakter sınıfına alarak tercih eder (örn. [.]). Normalde kaçış, bu durumda 1 byte kazandıracaktır\.
CSᵠ

[Java ile kaçması gerektiğini unutmayın . Ancak, ICU'dan (Android ve iOS'ta kullanılır) veya .NET'ten emin değilsiniz.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

18

ASCII tablosundaki tüm yazdırılabilir karakterleri eşleştirmek için basit bir düzenli ifade .

[ -~]

1
saf bir ustalık, standart bir ABD klavyesinden tüm karakterleri! not: standart ascii tablosu (genişletilmiş aralık 127-255 dahil değil
CSᵠ

Sık kullanıyorum, ancak ortak bir "normal" karakter eksik: TAB. Diğer yerel ayarların başarısız olacağı için LC_ALL = "C" (veya benzeri) kullandığınızı varsayar.
Olivier Dulac,

ASCII tablosunda herhangi bir karakter aralığını belirtmek için kısa çizgi kullanılabilir mi? Tüm regex lezzetleri için işe yarıyor mu?
Josh Withee,

14

Regex lezzetlerini bilin

Düzenli ifadelerin temelde dilden agnostik olduğunu düşünen şaşırtıcı sayıda insan vardır. Bununla birlikte, tatlar arasında aslında oldukça büyük farklılıklar vardır ve özellikle kod golf için bunlardan bazılarını ve ilginç özelliklerini bilmek iyidir, böylece her görev için en iyisini seçebilirsiniz. İşte birkaç önemli aroma ve bunları diğerlerinden ayıran şey hakkında genel bir bakış. (Bu liste tam olarak tamamlanamıyor, ancak gerçekten göze batan bir şeyi özledim mi bana bildirin.)

Perl ve PCRE

Bunları tek bir kabın içine atıyorum, çünkü Perl lezzetine pek aşina değilim ve çoğunlukla eşdeğerler (PCRE sonuçta Perl Uyumlu Düzenli İfadeler içindir). Perl lezzetinin en büyük avantajı, aslında regex ve ikame içinden Perl kodunu çağırabilmenizdir.

  • Özyineleme / alt yordamlar . Muhtemelen golf oynamak için en önemli özellik (sadece birkaç çeşitte var olan).
  • Şartlı desenler (?(group)yes|no).
  • Destekler ile yedek dizesindeki davanın değiştirmek \l, \u, \Lve \U.
  • PCRE, her bir alternatifin farklı (ancak sabit) bir uzunluğa sahip olabileceği göz alıcı alanlarda değişime izin verir. (Perl de dahil olmak üzere çoğu lezzet, genel bir sabit uzunluğa sahip olmak için göz alıcı gerektirir.)
  • \G Bir eşleşmeyi önceki eşleşmenin sonuna
  • \K maçın başlangıcını sıfırlamak için
  • PCRE, hem Unicode karakter özelliklerini hem de komut dosyalarını destekler .
  • \Q...\Edaha uzun karakterlerden kaçmak için. Birçok meta karakter içeren bir dizeyle eşleşmeye çalıştığınızda kullanışlıdır.

.AĞ

Bu, muhtemelen sadece çok az eksiklik olan en güçlü lezzet.

Golf açısından önemli bir eksiklik, diğer bazı tatlar gibi iyelik miktarlarını desteklememesidir. Bunun yerine .?+yazmak zorundasınız (?>.?).

Java

  • Bir hata nedeniyle (bkz. Ek) Java, sınırlı bir değişken uzunluktaki gözbebeği türünü destekler: .*şimdi bir gözatmaya başlayabileceğiniz yerden dizgenin başlangıcına kadar göz atabilirsiniz (?<=(?=lookahead).*).
  • Karakter sınıflarının birleşmesini ve kesişimini destekler.
  • "Unicode scriptleri, blokları, kategorileri ve ikili özellikleri" karakter sınıflarıyla Unicode için en geniş desteğe sahiptir .
  • \Q...\E Perl / PCRE'deki gibi.

Yakut

Son versiyonlarda, bu lezzet, alt rutin çağrıları da içeren PCRE kadar güçlüdür. Java gibi, karakter sınıflarının birleştirilmesini ve kesişmesini de destekler. Özel bir özellik, onaltılık basamaklar için yerleşik karakter sınıfıdır: \h(ve olumsuzlananlar \H).

Golf oynamanın en kullanışlı özelliği Ruby'nin miktar belirleyicileri nasıl kullandığıdır. En önemlisi, nicelikleri parantez olmadan yerleştirmek mümkündür. .{5,7}+çalışır ve yapar .{3}?. Aynı zamanda, diğer tatların çoğunun aksine, bir niceleyici üzerindeki alt bağın kullanılmaması 0durumunda, örneğin .{,5}eşdeğerdir .{0,5}.

Subroutinler gelince, PCRE'nin subroutines ve Ruby'nin değişmezler arasında büyük fark, Ruby'nin sözdizimi bir bayt daha uzun olmasıdır (?n)vs \g<n>ama PCRE bir altprogram tamamlandıktan sonra yakalar sıfırlar oysa Ruby'nin modüller, kaynak yakalamak için kullanılabilir.

Son olarak, Ruby, çizgiyle ilgili değiştiriciler için diğer pek çok tada göre farklı semantiklere sahiptir. Genellikle mdiğer lezzetlerde denilen değiştirici daima Ruby'dedir. Yani ^ve $her zaman başını ve sonunu maç hattı değil sadece başlangıç ve dize sonu. Eğer bu davranışı gerekiyorsa bu size bayt kurtarabilirsin ama bunu yapmazsanız Değiştirmeye gerekecek, çünkü ekstra bayt mal olacak ^ve $birlikte \Ave \zsırasıyla. Buna ek olarak, genellikle denilen değiştirici s( .eşleşen satırları besleyen) myerine Ruby denir . Bu, bayt sayısını etkilemez, ancak karışıklığı önlemek için akılda tutulmalıdır.

piton

Python'un katı bir lezzeti var, ama başka hiçbir yerde bulamayacağınız özellikle kullanışlı özelliklerin farkında değilim.

Bununla birlikte , modülün bir noktada değiştirilmesi amaçlanan ve birçok ilginç özellik içeren alternatif bir lezzet vardır re. Özyinelemeye, değişken uzunluklu görünümlere ve karakter sınıfı birleştirme operatörlerine destek eklemenin yanı sıra, bulanık eşleştirme özelliğine de sahiptir . Temelde, izin verilen bir dizi hata (yerleştirme, silme, değiştirme) belirtebilirsiniz; motor size yaklaşık eşleşmeler de verecektir.

ECMAScript

ECMAScript tadı çok sınırlıdır ve bu nedenle golf oynamak için nadiren kullanışlıdır. Bunun için tek yol , koşulsuz olarak başarısız olan boş karakter sınıfının yanı sıra herhangi bir karakterle eşleşmesi gereken olumsuz karakter [^] karakteridir [](normalin aksine (?!)). Ne yazık ki, lezzet normal problemler için ikincisini faydalı kılan hiçbir özelliğe sahip değildir.

Lua

Lua'nın oldukça kendine özgü bir tadı vardır; bu da oldukça sınırlıdır (örneğin, grupları bile ölçemezsiniz) ancak bir avuç yararlı ve ilginç özellik içerir.

  • Noktalama işaretleri, büyük / küçük harf karakterleri ve onaltılık sayılar dahil yerleşik karakter sınıfları için çok sayıda kısa yol bulunur .
  • İle %bçok kompakt bir sözdizimi destekleyen dengeli dizeleri eşleşecek. Örneğin, %b()a (ve daha sonra her şeyi eşleştirmeye eşleştirir )(iç eşleşen çiftleri doğru şekilde atlamak). (ve )burada herhangi iki karakter olabilir.

artırmak

Boost'un regex tadı aslında Perl'in. Ancak, dahil regex ikamesi için bazı güzel yeni özelliklere sahip vaka değişiklikler ve Koşullamalar . İkincisi, bildiğim kadarıyla Boost'a özgüdür.


Geriye doğru bakışta ileriye bakma, arkadaki sınır sınırını geçecektir. Java ve PCRE'de test edilmiştir.
n̴̖̋h̷͉a̷̭̿h̸̡̅ẗ̵̨d̷̰ĥ̷̳

.?+Eşdeğer değil .*mi?
Hesap MakinesiFeline

@CalculatorFeline İlki, sahip olduğu 0 veya 1 nicelik belirtecidir (iyelik dereceli niteleyicileri destekleyen tatlarda), ikincisi 0 veya daha fazla niceleyicidir.
Martin Ender

@CalculatorFeline ah karışıklığı anlıyorum. Bir yazım hatası vardı.
Martin Ender

13

Karakter sınıflarını bil

Regex tatlarının çoğu önceden tanımlanmış karakter sınıflarına sahiptir. Örneğin \d, üç bayttan daha kısa olan bir ondalık basamakla eşleşir [0-9]. Evet, \dbazı tatlarda da Unicode rakamlarıyla eşleşebileceklerinden biraz farklı olabilirler, ancak çoğu zorluk için bu bir fark yaratmaz.

Çoğu regex lezzetinde bulunan bazı karakter sınıfları:

\d      Match a decimal digit character
\s      Match a whitespace character
\w      Match a word character (typically [a-zA-Z0-9_])

Ek olarak, ayrıca:

\D \S \W

Yukarıdakilerin olumsuz versiyonları.

Lezzetinizi, sahip olabileceği herhangi bir ek karakter sınıfı için kontrol ettiğinizden emin olun. Örneğin, PCRE'nin \Ryeni satırlar var ve Lua'da küçük harf ve büyük harf gibi sınıflar bile var.

(Bunları işaret ettiği için @HamZa ve @ MartinBüttner'e teşekkürler)


3
\RPCRE'deki yeni hatlar için.
HamZa

12

Yakalamayan gruplarla uğraşma (...)

Bu ipucu (en azından) tüm popüler Perl'den ilham alan lezzetler için geçerlidir.

Bu açık olabilir, ancak (golf oynamıyorken), (?:...)mümkün olduğunda ele geçirmeyen grupları kullanmak iyi bir uygulamadır . Bu iki ekstra karakter ?:, golf oynarken çok israf ediyor, bu yüzden onları geri almayacak olsanız bile, sadece yakalama grupları kullanın.

Gerçi bir (nadir) istisna vardır: Eğer geribaşvuru grubuna gerçekleşmesi halinde 10en az 3 kez, gerçekte olmayan bir yakalama gruba önceki bir grup çevirerek bayt tasarruf, tüm bu tür anlamına \10ler haline \9ler. ( 11En az 5 kez grup kullanıyorsanız, benzer hileler geçerlidir .)


10'u 3 istediğinde neden 11'in buna değmesi için 5'e ihtiyacı var?
Nic Hartley

1
@QPaysTaxes bir kerede $9yerine bir kez kullanılabiliyorsa $10veya bir $11kez kullanılabiliyorsa, kaydeder. Torna $10içine $9birini gerektiren ?:üç gerekir, böylece iki bayt, $10bir şeyler kurtarmaya s. Torna $11içine $9iki gerektirir ?:beş gerekir, böylece dört bayt s $11şeyi korumaya s (veya beş $10ve $11kombine).
Martin Ender

10

Desen yeniden kullanımı için özyineleme

Bir avuç lezzet özyinelemeyi destekler ( bildiğim kadarıyla Perl, PCRE ve Ruby). Özyinelemeli sorunları çözmeye çalışmıyor olsanız bile, bu özellik daha karmaşık desenlerde çok fazla bayt tasarrufu sağlayabilir . Bu grubun kendi içinde başka bir (adlandırılmış veya numaralandırılmış) gruba çağrı yapmaya gerek yoktur. Regex'inizde birkaç kez görünen belirli bir düzeniniz varsa, sadece gruplayın ve o grubun dışına bakın. Bu, normal programlama dillerindeki bir alt rutinden farklı değildir. Yani yerine

...someComplexPatternHere...someComplexPatternHere...someComplexPatternHere... 

Perl / PCRE’de yapabilecekleriniz:

...(someComplexPatternHere)...(?1)...(?1)...

veya Ruby'de:

...(someComplexPatternHere)...\g<1>...\g<1>...

Bu ilk grup olması koşuluyla (tabii ki, özyinelemeli aramada istediğiniz numarayı kullanabilirsiniz).

Bunun bir backreference ( ) ile aynı olmadığını unutmayın \1. Geri referanslar, grubun geçen seferkilerle aynı dizeyle tam olarak eşleşiyor. Bu alt rutin çağrılar aslında modeli tekrar değerlendirir. someComplexPatternHereUzun bir karakter sınıfı almak için örnek olarak :

a[0_B!$]b[0_B!$]c[0_B!$]d

Bu gibi bir şey eşleşir

aBb0c!d

Davranışı korurken buradaki referansları kullanamayacağınızı unutmayın. Bir geribaşvuru yukarıdaki dize başarısız, çünkü olur Bve 0ve !aynı değildir. Bununla birlikte, alt rutin çağrılarla, desen aslında yeniden değerlendirilir. Yukarıdaki model tamamen eşdeğerdir

a([0_B!$])b(?1)c(?1)d

Alt rutin çağrılarda yakalama

Perl ve PCRE için bir uyarı notu: eğer 1yukarıdaki örnekteki grup başka gruplar içeriyorsa, alt rutin çağrılar yakalamalarını hatırlamayacaktır. Bu örneği düşünün:

(\w(\d):)\2 (?1)\2 (?1)\2

Bu olacak değil maç

x1:1 y2:2 z3:3

çünkü alt rutin çağrılar geri döndükten sonra, yeni grup yakalama işlemi 2atılır. Bunun yerine, bu desen bu dizeyle eşleşir:

x1:1 y2:1 z3:1

Bu değişmez arama Ruby, farklı do eşdeğer Yakut regex yüzden, onların yakalar korumak (\w(\d):)\2 \g<1>\2 \g<1>\2yukarıdaki örneklerin ilk eşleşir.


\1Javascript için kullanabilirsiniz . Ve PHP de (sanırım).
Ismael Miguel

5
@IsmaelMiguel Bu bir geri dönüş değildir. Bu aslında modeli tekrar değerlendirir. Örneğin (..)\1, eşleşecek, ababancak başarısız, abbaoysa (..)(?1)ikincisiyle eşleşecektir. Aslında, geçen sefer tam olarak eşleştiği şeyle eşleşmek yerine ifadenin yeniden uygulandığı anlamında bir alt rutin çağrı.
Martin Ender

Vay, hiçbir fikrim yoktu! Her gün yeni bir şey öğrenmek
Ismael Miguel

.NET'te (veya bu özelliği olmayan diğer lezzetlerde):(?=a.b.c)(.[0_B!$]){3}d
jimmy23013 13:15

Bu belirli örneğe çok özel görünen @ user23013. Belirli bir alt yolu çeşitli görünümlerde yeniden kullanırsam bunun uygulanabilir olduğundan emin değilim.
Martin Ender

9

Eşleşmenin başarısız olmasına neden olma

İşlemsel sorunları çözmek veya normal olmayan dilleri eşleştirmek için regex kullanırken, dizginin neresinde olduğunuza bakmaksızın örüntü dalının bozulmasına neden olabilir. Saf yaklaşım, boş bir negatif bakış açısı kullanmaktır:

(?!)

İçindekiler (boş desen) her zaman eşleşir, bu nedenle negatif görünüm her zaman başarısız olur. Ancak, çoğu zaman çok daha basit bir seçenek var: sadece girdide asla görünmeyeceğini bildiğiniz bir karakter kullanın. Örneğin, girişinizin her zaman yalnızca rakamlardan oluşacağını biliyorsanız, yalnızca

!

veya arızalanmaya neden olan herhangi bir rakam olmayan, meta olmayan karakter.

Girişiniz potansiyel olarak herhangi bir alt dizgi içerebilse bile, bundan daha kısa yollar vardır (?!). Ankrajların, ucun aksine bir desen içinde görünmesine izin veren herhangi bir lezzet, aşağıdaki 2 karakterlik çözümlerden herhangi birini kullanabilir:

a^
$a

Ancak bazı tatlar tedavi unutmayın ^ve $onlar besbelli aslında çapa olarak anlamı yok, çünkü bu konumlarda değişmez karakter olarak.

ECMAScript lezzetinde oldukça şık 2 karakterli bir çözüm de var

[]

Bu, bir sonraki karakterlerin sınıftaki karakterlerden biri olduğundan emin olmaya çalışan boş bir karakter sınıfıdır - ancak sınıfta karakter yoktur, bu nedenle her zaman başarısız olur. Karakter sınıfları genellikle boş olamayacağından, bunun başka hiçbir lezzette işe yaramayacağını unutmayın.


8

Sizi optimize edin VEYA

RegEx'inizde 3 veya daha fazla alternatifiniz olduğunda:

/aliceblue|antiquewhite|aquamarine|azure/

Ortak bir başlangıç ​​olup olmadığını kontrol edin:

/a(liceblue|ntiquewhite|quamarine|zure)/

Ve belki de ortak bir son olabilir?

/a(liceblu|ntiquewhit|quamarin|zur)e/

Not: 3 sadece bir başlangıçtır ve aynı uzunlukta hesaba katılır, 4+ fark yaratır


Peki ya hepsinin ortak bir ön eki yoksa? (boşluk yalnızca netlik için eklendi)

/aliceblue|antiquewhite|aqua|aquamarine|azure
|beige|bisque|black|blanchedalmond|blue|blueviolet|brown|burlywood
|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan/

3+ kuralı mantıklı olduğu sürece onları gruplandırın:

/a(liceblue|ntiquewhite|qua|quamarine|zure)
|b(eige|isque|lack|lanchedalmond|lue|lueviolet|rown|urlywood)
|c(adetblue|hartreuse|hocolate|oral|ornflowerblue|ornsilk|rimson|yan)/

Ya da entropi, sizin temponuzu yerine getirirse, genelleştirin :

/\w(liceblue|ntiquewhite|qua|quamarine|zure
|eige|isque|lack|lanchedalmond|lue|lueviolet|rown|urlywood
|adetblue|hartreuse|hocolate|oral|ornflowerblue|ornsilk|rimson|yan)/

^ Bu durumda biz hiç alamadık clueveya eminizcrown slack Ryan

Bu, "bazı testlere göre" , başlaması için bir çapa sağladığı için performansı da arttırır .


1
Ortak başlangıç ​​veya bitiş bir karakterden uzunsa, iki grubu gruplamak bile bir fark yaratabilir. Gibi aqua|aquamarineaqua(|marine)ya aqua(marine)?.
Paŭlo Ebermann

6

Bu oldukça basittir, ancak belirtmeye değer:

Eğer karakter sınıfını tekrar bulursanız [a-zA-Z]muhtemelen sadece kullanabilirsiniz [a-z]ve ekleme i(vaka i nsensitive değiştirici) sizin regex için.

Örneğin, Ruby'de, aşağıdaki iki regex eşdeğerdir:

/[a-zA-Z]+\d{3}[a-zA-Z]+/
/[a-z]+\d{3}[a-z]/i - 7 bayt daha kısa

Bu nedenle, diğer değiştiriciler de toplam sürenizi kısaltabilir. Bunu yapmak yerine:

/(.|\n)/

HİÇBİR karakterle eşleşen (çünkü nokta yeni çizgiyle eşleşmiyor), nokta eşlemeli yeni çizgileri yapan s satır içi değiştiricisini kullanın s.

/./s - 3 bayt daha kısa


Ruby'de, regex için bir ton yerleşik Karakter Sınıfı vardır. Bu sayfaya bakın ve "Karakter Özellikleri" ni arayın.
En iyi örnek "Para Birimi Simgesi" dir. Wikipedia'ya göre , bir sürü olası para birimi simgesi var ve bunları bir karakter sınıfına koymak çok pahalı olurdu ( [$฿¢₡Ð₫€.....]), ancak bunlardan herhangi birini 6 baytta eşleştirebilirsiniz:\p{Sc}


1
sDeğiştiricinin desteklenmediği JavaScript dışında . :( Ama orada JavaScript'in özel /[^]/numarasını kullanabilirsiniz .
manatwork

Bunun (.|\n)bazı tatlarda bile çalışmadığını unutmayın , çünkü .çoğu zaman diğer hat ayırıcılarla da eşleşmez. Ancak, bunu yapmanın geleneksel yolu (onsuz s), [\s\S]aynı bayt olandır (.|\n).
Martin Ender

@ MartinBüttner, fikrim diğer ilgili ipuçlarıyla biten diğer satırlarla birlikte tutmaktı. Fakat bu cevabın değiştiriciler hakkında daha fazla olduğunu düşünüyorsanız, tekrar basarsanız itirazım yok.
Manatwork

@manworkwork tamamlandı (ve ayrıca ES ile ilgili olmayan özel bir numara da ekledi)
Martin Ender

6

Basit bir dil ayrıştırıcısı

Bir RE benzeri ile çok basit bir çözümleyici oluşturabilirsiniz \d+|\w+|".*?"|\n|\S. Eşleştirmeniz gereken belirteçler RE 'veya' karakteriyle ayrılır.

RE motoru, metindeki şu anki konumda eşleşmeye çalıştığında, ilk deseni, sonra ikincisini vb. Deneyecek. . Sipariş önemlidir. Biz verdiyseniz \Sönce gelen terimi \d+terim, \Sbizim ayrıştırıcı kıracak olmayan herhangi uzay karakterine ilk eşleşir.

".*?"Biz sadece bir defada bir dize eşleşecek şekilde dize eşleştirme aracı olmayan açgözlü değiştirici kullanır. RE'niz açgözlü olmayan işlevlere sahip değilse, "[^"]*"hangisini eşdeğerdir kullanabilirsiniz .

Python Örneği:

text = 'd="dogfinder"\nx=sum(ord(c)*872 for c in "fish"+d[3:])'
pat = r'\d+|\w+|".*?"|\n|\S'
print re.findall(pat, text)

['d', '=', '"dogfinder"', '\n', 'x', '=', 'sum', '(', 'ord', '(', 'c', ')',
    '*', '872', 'for', 'c', 'in', '"fish"', '+', 'd', '[', '3', ':', ']', ')']

Golf Python Örneği:

# assume we have language text in A, and a token processing function P
map(P,findall(r'\d+|\w+|".*?"|\n|\S',A))

Desenleri ve sıralarını, eşleştirmeniz gereken dil için ayarlayabilirsiniz. Bu teknik JSON, temel HTML ve sayısal ifadeler için iyi çalışır. Python 2 ile birçok kez başarıyla kullanılmıştır, ancak diğer ortamlarda çalışacak kadar genel olmalıdır.


6

\K olumlu bakma yerine

PCRE ve Perl \K, eşleşmenin başlangıcını sıfırlayan çıkış sırasını destekler . Bu, ab\Kcdgiriş dizginizin içermesini gerektirecek abcdancak raporlanan eşleşme yalnızca olacaktır cd.

Desenin başlangıcında (muhtemelen en muhtemel yer olan) pozitif bir gözetleme kullanıyorsanız, çoğu durumda \Kbunun yerine kullanabilir ve 3 bayt kaydedebilirsiniz:

(?<=abc)def
abc\Kdef

Bu çoğu amaç için eşdeğerdir , ancak tamamen değildir. Farklılıklar yanlarında hem avantaj hem de dezavantaj getiriyor:

  • Upside: PCRE ve Perl isteğe bağlı uzunluktaki göz atmalarını desteklemiyor (yalnızca .NET kullanıyor). Yani, böyle bir şey yapamazsın (?<=ab*). Ama onunla \Könüne herhangi bir desen koyabilirsin! Çok ab*\Kçalışıyor. Bu aslında uygulanabilir olduğu durumlarda bu tekniği çok daha güçlü kılar.
  • Upside: Manzaralar geri dönüş yapmıyor. Bu, daha sonra geri tepmek üzere göze çarparak bir şey yakalamak istiyorsanız geçerlidir, ancak bunların hepsi geçerli eşleşmelere yol açan birkaç olası yakalama vardır. Bu durumda, regex motoru sadece bu olasılıklardan birini deneyecekti. \KRegex'in bu kısmını kullanırken her şeyde olduğu gibi geri izleniyor.
  • Dezavantajı: Muhtemelen bildiğiniz gibi, bir regex'in birkaç maçı üst üste gelemez. Genellikle, görünüşler bu sınırlama etrafında kısmen çalışmak için kullanılır, çünkü görünüş, daha önce bir eşleşme tarafından tüketilmiş olan ipin bir kısmını doğrulayabilir. Dolayısıyla, takip eden tüm karakterleri eşleştirmek abistiyorsanız, kullanabilirsiniz (?<=ab).. Giriş verilen

    ababc
    

    bu, ikinci ave aynı olur c. Bu , çoğaltılamaz \K. Eğer kullansaydın ab\K., sadece ilk eşleşmeyi elde edersin, çünkü şimdi abbir görünüşe göre değildir.


Eğer bir model \Kkaçış dizisini pozitif bir iddia içinde kullanırsa, başarılı bir eşleşmenin bildirilen başlangıcı eşleşmenin sona ermesinden daha büyük olabilir.
HWND

@hwnd Benim demek verilen olmasıdır ababcikinci hem maç için hiçbir yolu yoktur, ave cile \K. Sadece bir eşleşme elde edersiniz.
Martin Ender

Haklısın, özelliğin kendisi ile değil. Demir \G
atmanız

@hwnd Ah Amacınızı şimdi görüyorum. Ama sanırım bu noktada (golf perspektifinden) olumsuz bir bakışla daha iyi durumdasınız, çünkü .son maçın aslında bir olduğundan emin olamadığınız için aslında buna ihtiyaç duyabilirsiniz a.
Martin Ender

1
\ K =) kullanımının ilginç kullanımı
hwnd

5

Herhangi bir karakterin eşleştirilmesi

ECMAScript tadı herhangi bir karakterle eşleştiren sdeğiştiricilerden yoksundur .(yeni satırlar dahil). Bu, tamamen rastgele karakterleri eşleştirmenin tek karakterli bir çözümü olmadığı anlamına gelir. Diğer tatlardaki standart çözüm (biri snedense kullanmak istemiyorsa ) [\s\S]. Ancak, ECMAScript boş karakter sınıflarını destekler ve dolayısıyla daha kısa çok alternatife sahip (bildiğim kadarıyla) sadece lezzet: [^]. Bu, reddedilen bir boş karakter sınıfıdır - yani herhangi bir karakterle eşleşir.

Diğer tatlar için bile, bu teknikten öğrenebiliriz: kullanmak istemiyorsak s(örneğin ., başka yerlerde genel anlamını hala gerektirmemiz gerekiyorsa ), hem newline hem de yazdırılabilir karakterlerle eşleşmenin daha kısa bir yolu olabilir, bildiğimiz bazı karakterler olması kaydıyla, girişte görünmüyor. Diyelim, yeni satırlarla sınırlandırılmış numaraları işliyoruz. Öyleyse, herhangi bir karakterle eşleşebiliriz [^!], çünkü bunun !dizenin bir parçası olmayacağını biliyoruz . Bu naif [\s\S]veya iki bayttan tasarruf eder [\d\n].


4
Perl'de, bir moddan etkilenmemesi dışında, \Ntam olarak modun .dışında ne anlama geldiği anlamına gelir /s.
Konrad Borowski

4

Atom grupları ve sahiplik niceleyicileri kullanın

I atom grupları (bulunan (?>...)) ve iyelik nicelik ( ?+, *+, ++, {m,n}+) golf bazen çok yararlı. Bir dizeyle eşleşir ve daha sonra geri izlemeye izin vermez. Bu nedenle, yalnızca regex motoru tarafından bulunan ilk eşleşen dizeyle eşleşir.

Örneğin: Başlangıçta tek sayısı aolan, daha fazlasını izlemeyen bir dizeyle eşleştirmek için a, şunları kullanabilirsiniz:

^(aa)*+a
^(?>(aa)*)a

Bu, .*serbestçe gibi şeyleri kullanmanızı sağlar ve bariz bir eşleşme varsa, düzeninizi bozabilecek çok fazla veya çok az karakterle eşleşen başka bir olasılık olmaz.

.NET regex'te (sahip olduğu nicelik ölçütlere sahip değildir), bunu, en fazla 3 (en fazla 30) kez (en iyi şekilde golf oynamamaktadır) en fazla 3 katına çıkarmak için kullanabilirsiniz.

(?>((?<-1>){3}|){10})

1
ECMAscript'te de sahiplik
niteleyicileri

4

Alt ifadeden sonra yakalanan grubu unut (PCRE)

Bu regex için:

^((a)(?=\2))(?!\2)

Grup 1'den sonra \ 2'yi silmek istiyorsanız özyinelemeyi kullanabilirsiniz:

^((a)(?=\2)){0}(?1)(?!\2)

Bir aaönceki olmazsa eşleşecek . Bazen yerine ??bile kullanabilirsiniz .?{0}

Bu, özyinelemeler çok kullandıysanız ve regex'inizin farklı yerlerinde bazı geri referansların veya koşullu grupların ortaya çıkması durumunda faydalı olabilir.

Ayrıca, atom gruplarının PCRE'deki özyinelemeler için varsayıldığını unutmayın. Yani bu tek bir harfle eşleşmeyecek a:

^(a?){0}(?1)a

Henüz diğer lezzetlerde denemedim.

Genel bakış için bu amaçla çift negatif de kullanabilirsiniz:

^(?!(?!(a)(?=\1))).(?!\1)

4

İsteğe bağlı ifadeler

Bunu hatırlamak bazen yararlı olur.

(abc)?

olduğu , çoğunlukla aynı

(abc|)

Yine de küçük bir fark var: ilk durumda, grup ya yakalar abcya da hiç yakalamaz. İkinci durum, bir geri dönüşün koşulsuz olarak başarısız olmasına neden olacaktır. İkinci ifadede, grup yakalama ya olacak abcya sonuncu durumda bir geribaşvuru yapacak boş bir dize, maç koşulsuz. İkinci davranışı taklit etmek için, ?iki bayta mal olacak başka bir gruptaki her şeyi çevrelemeniz gerekir:

((abc)?)

Bu sürüm |aynı zamanda, ifadeyi yine de başka bir grup şeklinde sarmak istediğinizde ve çekimi önemsemediğiniz zaman kullanışlıdır:

(?=(abc)?)
(?=abc|)

(?>(abc)?)
(?>abc|)

Son olarak, bu numara ?çiğ formunda bile bir bayttan tasarruf ettiği yerde (ve sonuçta diğer grup formlarıyla birleştirildiğinde 3 bayt): unungreedy'e uygulanabilir :

(abc)??
(|abc)

1

Her zaman eşleşen birden fazla bakış açısı (.NET)

Her zaman eşleşen (alt ifadeleri yakalamak için) eşleşen 3 veya daha fazla sayıda lookahead yapınız varsa veya başka bir şey tarafından takip edilen bir lookahead üzerinde bir niceleyici varsa, bu nedenle mutlaka yakalanmamış bir grupta bulunmaları gerekir:

(?=a)(?=b)(?=c)
((?=a)b){...}

Bunlar daha kısa:

(?(?(?(a)b)c))
(?(a)b){...}

nerede abir esir grubun adı olmamalıdır. Başka bir parantez çifti eklemeden ve eklemeden |normal bir şey ifade etmek için kullanamazsınız .bc

Ne yazık ki, şartlı şartlardaki dengeleme grupları, pek çok durumda işe yaramaz hale gelen, hatalı görünüyordu.

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.