Calibre’de kurallı ifadelerin kullanımına dair her şey

Kurallı ifadeler, calibrenin birçok yerinde e-kitap içerik ve üstverinin çok yönlü işlemesi için kullanılan bir özellik. Bu öğretici başlangıç, size calibrede kurallı ifadelerin kullanımına başlamanız için yumuşak bir tanıtım.

Öncelikle, bir uyarı ve bir kaç cesaret kelimesi

Bu, kaçınılmaz şekilde bir şekilde teknik olacaktır- neticede, düzenli ifadeler teknik şeyler yapmak için teknik araçlardır. Karmaşık ya da anlaşılmaz görünebilecek bazı kavramlar veya jargon kullanmam gerekecek. Bu kavramları olabildiğince basit anlatmaya çalışacağım, ama hiç anlatmadan da yapamam. Bunu söyledikten sonra, gördüğünüz jargonlar cesaretinizi kırmasın, herşeyi baştan anlatmaya çalışıyorum. Ve düzenli ifadeler kara büyü ya da gizli saklı şeyler gibi görünseler de (ya da rastgele karakter dizileri ve işaretler gibi), bu kadar karmaşık olmadıkları konusunda sözüme güvenebilirsiniz. Düzenli ifadeleri gerçekten anlayan insanlar bile daha karmaşık olanları okumakta zorlanabilirler, ama yazması o kadar da zor değildir- ifadeyi adım adım oluşturursunuz. Şimdi bir adım atın ve beni tavşan deliğine doğru takip edin.

Calibre’de nerelerde düzenli ifadeler kullanabilirsiniz?

There are a few places calibre uses regular expressions. There’s the Search & replace in conversion options, metadata detection from filenames in the import settings and Search & replace when editing the metadata of books in bulk. The calibre book editor can also use regular expressions in its search and replace feature.

Yahu nedir bu düzenli ifade?

Bir düzenli ifade karakter dizisi kümelerini tanımlama yöntemidir. Tek bir düzenli ifade değişik belirli sayıda karakter dizisiyle eşleşebilir. Düzenli ifadeyi bu kadar güçlü kılan budur – çok sayıda çeşitlemeyi ifade edecek öz bir yöntemdir.

Not

I’m using string here in the sense it is used in programming languages: a string of one or more characters, characters including actual characters, numbers, punctuation and so-called whitespace (linebreaks, tabulators etc.). Please note that generally, uppercase and lowercase characters are not considered the same, thus “a” being a different character from “A” and so forth. In calibre, regular expressions are case insensitive in the Search bar, but not in the conversion options. There’s a way to make every regular expression case insensitive, but we’ll discuss that later. It gets complicated because regular expressions allow for variations in the strings it matches, so one expression can match multiple strings, which is why people bother using them at all. More on that in a bit.

Açıklamak istemez misin?

Peki, zaten bu yüzden burdayız. Öncelikle, düzenli ifadelerdeki en önemli kavram şudur: Bir karakter dizisi kendisiyle eşleşen bir düzenli ifadedir. Yani, "Hello, World!" karakter dizisiyle eşleşen bir düzenli ifade istesem, kullanmam gereken düzenli ifade Hello, World!``olurdu. Ve evet, gerçekten bu kadar basit. Fark edeceğiniz üzere, bu *yalnızca* bire bir karakter dizisiyle eşleşir yani ``"Hello, World!" ile, "Hello, wOrld!" veya "hello, world!" ile ya da başka bir çeşidiyle değil.

Çok kötü görünmüyor. Sırada ne var?

Bir sonraki iyi öğelerin başlangıcı olacak. Kurallı ifadelerin, çoklu dizelerle eşleşebileceğini söylediğimi hatırlıyor musunuz? Bu noktada iş biraz karmaşık hal alıyor. Diyelim ki, nispeten daha bir pratik çalışma olarak,

Güzel! Mantıklı gelmeye başladı!

Bunu söyleyeceğinizi umuyordum. Ama kendinizi hazırlayın, şimdi daha da iyi olacak! Kümeleri kullanarak bir çok karakterden biriyle eşleşme yapabileceğimizi öğrendik. Hatta bir karakter veya kümeyi tekrar kullanarak yukardaki sayfa numarası örneğinde gerekli ifade sayısını teke indirebilirsiniz. Evet, BİR! İlginizi çekti mi? Çekmeli! Şu şekilde çalışır: Bazı özel karakterler, “+”, “?” ve “*”, önlerindeki elemanı tekrarlarlar. (Eleman ya tek bir karakter, ya bir karakter kümesi, kaçış serisi ya da bir grup demektir (son ikisine daha sonra göz atacağız)- kısaca, düzenli ifadedeki herhangi tekil öğe.). Bu karakterlere genel arama karakterleri ya da nicelik sözcükleri denir. Daha açık olmak gerekirse, “?” önceki elemandan 0 veya 1 tane ile eşleşir, “*” 0 veya daha fazla ile ve “+” 1 veya daha fazla ile eşleşme demektir. Birkaç örnek: a? ifadesi ya “” (boş karakter dizisi, bu durumda pek faydalı değil) veya “a”, a* ifadesi “”, “a”, “aa” veya bir satırdaki herhangi sayıda a ile, ve son olarak, a+ ifadesi “a”, “aa” veya bir satırdaki herhangi sayıda a ile eşleşir (Not: boş karakter dizisiyle eşleşmez!). Kümeler için de olay aynıdır: [0-9]+ ifadesi tüm tam sayılarla eşleşir! Ne düşündüğünüzü biliyorum, ve haklısınız: Bunu yukardaki sayfa numaraları eşleştirmesinde kullansak, bu tüm sayfa numaralarıyla eşleşen bir ifade olmaz mıydı? Evet, Page [0-9]+ of 423 ifadesi bu kitaptaki tüm sayfa numaralarıyla eşleşirdi!

Not

Bu nicelik sözcükleriyle ilgili bir not: Genellikle olabildiğince çok metinle eşleşmeye çalışırlar, yani kullanırken dikkatli olun. Buna “hırslı davranış” denir - neden olduğunu anladığınıza eminim. Bu, bir etiketi eşleştirmeye çalıştığınızda problem olmaya başlar. "<p class="calibre2">Başlık buraya</p>" karakter dizisi örneğini ele alalım ve açılış etiketini eşleştirmek istediğinizi farz edelim (ilk açı işaretleri arasındaki kısım, etiketlerle ilgili daha sonra konuşacağız). <p.*> ifadesinin bu etiketle eşleşeceğini düşünebilirsiniz, ama aslında tüm karakter dizisiyle eşleşir! (“.” karakteri başka bir özel karakterdir. Satır sonları hariç herşeyle eşleşir, yani, .* ifadesi düşünebileceğiniz tüm tek satırlar ile eşleşir.) Bunun yerine <p.*?> kullanmayı deneyin, bu "*" nicelik sözcüğünün hırslı olmamasını sağlar. Bu ifade yalnızca ilk açılış etiketiyle eşleşirdi, istediğimiz gibi. Aslında bunu elde etmenin bir yolu daha vardır: <p[^>]*> ifadesi aynı açılış etiketiyle eşleşir- sonraki kısımda neden olduğunu göreceksiniz. Şimdilik bir düzenli ifadeyi yazmanın birden çok yolu olabileceğini not edin.

Bu özel karakterler değişik ve temiz, ama ya bir nokta ya da soru işareti eşleştirmek istersem?

Bunu da tabi ki yapabilirsiniz: Herhangi özel karakterin önüne ters bölü işareti koyarsanız, bu karakter herhangi bir özel anlamı olmadan neyse o olarak yorumlanır. Bir ters bölü işareti çifti ve ardından gelen tek bir karaktere kaçış düzeni denir, ve özel bir karakterin önüne ters bölü koymaya da karakteri kaçırmak denir. Kaçış düzeni tek bir öğe gibi yorumlanır. Tabi ki yalnızca özel karakterleri kaçırmaktan fazlasınnı yapan kaçış düzenleri de vardır, örneğin "\t" bir sekme anlamına gelir. Bazı kaçış düzenlerinden daha sonra bahsedeceğiz. Ve bu arada, bu özel karakterlerle ilgili olarak: Bu girişte bahsi geçen karakterleri bir fonksiyona sahipmiş ve karakterin aslını kullanmak için kaçırmanız gerekiyormuş gibi düşünebilirsiniz.

Peki, en kullanışlı kümeler hangileri?

Soracağınızı biliyordum, Kullanışlı kümelerden bazıları tek bir sayıyla eşleşen [0-9], tek bir küçük harfle eşleşen [a-z], tek bir büyük harfle eşleşen [A-Z], tek bir harfle eşleşen [a-zA-Z] ve tel bir harf ya da sayıyla eşleşen [a-zA-Z0-9] olabilir. Ayrıca kısayol olarak bir kaçış düzeni kullanabilirsiniz:

\d is equivalent to [0-9]
\w is equivalent to [a-zA-Z0-9_]
\s is equivalent to any whitespace

Not

“Boşluk” yazdırılmayacak herşeyi ifade eden bir terimdir. Bu karakterler boşluk, sekme, satır besleme, form besleme ve satır başını içerir.

Kümelerle ilgili son bir not olarak, bir kümeyi herhangi bir karakter gibi ama kümedeki karakterler gibi tanımlayabileceğinizi söyleyelim. Bunu "^" karakterini kümedeki ilk karakter olarak ekleyerek yapabilirsiniz. Böylece, [^a] “a” olmayan herhangi bir karakterle eşleşir. Buna kümeyi tümleme denir. Daha önce gördüğümüz kaçış düzeni kısayolları de tümlenebilirler: "\D" sayı olmayan herhangi bir karakter demektir, yani [^0-9] ile eşittir. Diğer kısayollar da tahmin edeceğiniz üzere, küçük harf olan yerine büyük harf kullanarak tümlenebilir. Önceki kısımdan <p[^>]*> örneğine gidersek, kullandığı karakter kümesinin kapanan bir açı işareti dışındaki herhangi bir karakterle eşleştiğini görebilirsiniz.

Ama bir kaç çeşit karakter dizim varsa, işler karmaşıklaşıyor?

Fear not, life still is good and easy. Consider this example: The book you’re converting has “Title” written on every odd page and “Author” written on every even page. Looks great in print, right? But in e-books, it’s annoying. You can group whole expressions in normal parentheses, and the character "|" will let you match either the expression to its right or the one to its left. Combine those and you’re done. Too fast for you? Okay, first off, we group the expressions for odd and even pages, thus getting (Title)(Author) as our two needed expressions. Now we make things simpler by using the vertical bar ("|" is called the vertical bar character): If you use the expression (Title|Author) you’ll either get a match for “Title” (on the odd pages) or you’d match “Author” (on the even pages). Well, wasn’t that easy?

Tabi ki, grup parantezleri kullanmadan da dik çubuğu kullanabilirsiniz. Nicelik sözcüklerinin önlerindeki öğeleri tekrarladıklarını söylediğimi hatırlıyorsunuz değil mi? Dikey çubuk biraz daha değişik çalışır: “Title|Author” ifadesi de ya “Title” ya da “Author” karakter dizisiyle eşleşir, yukardaki örnekteki gibi gruplamayla. Dikey çubuk tüm ifade arasından önce geleni seçer ve takip eder. Yani, “Calibre” ve “calibre” karakter dizileriyle eşleşme istediğinizde ve yalnızca büyük harf- ve küçük harf “c” arasını seçmek istediğinizde , (c|C)alibre ifadesini kullanmanız gerekir, gruplama “c” nin seçildiğinden emin olmanızı sağlar. c|Calibre kullansaydınız, “c” karakterinde eşleşme alırdınız ya da “Calibre” karakter dizisinde, ki burada istediğimiz bu değil. Kısaca: şüphe duyarsanız, gruplamayı dikey çubukla kullanın.

Şunu atladın…

…bir dakika, gruplarla yapabileceğiniz bir tane son, gerçekten hoş şey var. Daha önce eşleşen bir grubunuz varsa, sonraki ifadelerde bu gruba başvurabilirsiniz: Gruplar 1 ile başlayarak numaralandırılır, ve başvurmak için grup numarasını kaçırmanız gerekir, yani beşinci gruba \5 ile başvurulur. “Test Test” karakter dizisinde ([^ ]+) \1 aradıysanız, tüm karakter dizisiyle eşleşirsiniz!

Başlangıçta, düzenli ifadeleri büyük küçük harf bağımsız yapabileceğimizi söylemiştin?

Yes, I did, thanks for paying attention and reminding me. You can tell calibre how you want certain things handled by using something called flags. You include flags in your expression by using the special construct (?flags go here) where, obviously, you’d replace “flags go here” with the specific flags you want. For ignoring case, the flag is i, thus you include (?i) in your expression. Thus, (?i)test would match “Test”, “tEst”, “TEst” and any case variation you could think of.

Another useful flag lets the dot match any character at all, including the newline, the flag s. If you want to use multiple flags in an expression, just put them in the same statement: (?is) would ignore case and make the dot match all. It doesn’t matter which flag you state first, (?si) would be equivalent to the above.

Galiba artık bu düzenli ifadeleri anlamaya başlıyorum… calibre’de bunları nasıl kullanırım?

Dönüştürmeler

Let’s begin with the conversion settings, which is really neat. In the Search & replace part, you can input a regexp (short for regular expression) that describes the string that will be replaced during the conversion. The neat part is the wizard. Click on the wizard staff and you get a preview of what calibre “sees” during the conversion process. Scroll down to the string you want to remove, select and copy it, paste it into the regexp field on top of the window. If there are variable parts, like page numbers or so, use sets and quantifiers to cover those, and while you’re at it, remember to escape special characters, if there are some. Hit the button labeled Test and calibre highlights the parts it would replace were you to use the regexp. Once you’re satisfied, hit OK and convert. Be careful if your conversion source has tags like this example:

Maybe, but the cops feel like you do, Anita. What's one more dead vampire?
New laws don't change that. </p>
<p class="calibre4"> <b class="calibre2">Generated by ABC Amber LIT Conv
<a href="http://www.processtext.com/abclit.html" class="calibre3">erter,
http://www.processtext.com/abclit.html</a></b></p>
<p class="calibre4"> It had only been two years since Addison v. Clark.
The court case gave us a revised version of what life was

(shamelessly ripped out of this thread). You’d have to remove some of the tags as well. In this example, I’d recommend beginning with the tag <b class="calibre2">, now you have to end with the corresponding closing tag (opening tags are <tag>, closing tags are </tag>), which is simply the next </b> in this case. (Refer to a good HTML manual or ask in the forum if you are unclear on this point.) The opening tag can be described using <b.*?>, the closing tag using </b>, thus we could remove everything between those tags using <b.*?>.*?</b>. But using this expression would be a bad idea, because it removes everything enclosed by <b>- tags (which, by the way, render the enclosed text in bold print), and it’s a fair bet that we’ll remove portions of the book in this way. Instead, include the beginning of the enclosed string as well, making the regular expression <b.*?>\s*Generated\s+by\s+ABC\s+Amber\s+LIT.*?</b> The \s with quantifiers are included here instead of explicitly using the spaces as seen in the string to catch any variations of the string that might occur. Remember to check what calibre will remove to make sure you don’t remove any portions you want to keep if you test a new expression. If you only check one occurrence, you might miss a mismatch somewhere else in the text. Also note that should you accidentally remove more or fewer tags than you actually wanted to, calibre tries to repair the damaged code after doing the removal.

Kitap Ekleme

Düzenli ifadelerin kullanılabileceği başka bir yer de dosya isimlerinden metadata çıkarmaktır. Bu özelliği ayarların “Kitap ekleme” kısmında bulabilirsiniz. Burada özel bir özellik vardır: Metadata alanları için alan isimlerini kullanabilirsiniz, örneğin (?P<title>) calibre’nin kitap başlığı olarak karakter dizisinin bu kısmını kullanacağı anlamına gelir. İzin verilen alan isimleri güzel bir test alanıyla beraber pencerelerde listelenir. Örnek: Klasik Metinler: The Divine Comedy by Dante Alighieri.mobi (Klasik İtalyan şiirini hepimiz sevdiğimizden, bu tabi ki zaten kitaplığınızda) veya Bilim Kurgu harikaları: The Foundation Trilogy by Isaac Asimov.epub gibi bir takım dosyaları içe aktarmak istediğinizi varsayalım. Bu kesinlikle calibre’nin anlamlı bir veri çıkaramayacağı bir isimlendirme şeması - çünkü metadata çıkarmak için kullandığı standart ifade (?P<title>.+) - (?P<author>[^_]+). Burada çalışacak bir düzenli ifade [a-zA-Z]+: (?P<title>.+) by (?P<author>.+) olurdu. Metadata alanı için olan grup içinde, alanın gerçekten neyle eşleşeceğini tanımlayan ifadeler kullanmanız gerektiğini de not alın lütfen. Ayrıca calibre’nin sağladığı test alanını kullanırken test dosya isminize dosya uzantısını da girmelisiniz, aksi halde çalışan bir ifadeniz olsa da hiçbir eşleşme almazsınız.

Metadata’nın toplu düzenlenmesi

Son kısım metadata alanlarında düzenli ifade arama ve değiştirme. Buna kitaplıktan birden çok kitap seçin toplu metadata düzenleme seçerek erişebilirsiniz. Bu son özelliği kullanırken çok dikkatli olun, çünkü kitaplığınıza Çok Kötü Şeyler yapabilir! Test alanlarını kullanarak ifadelerinizin yapmasını istediklerinizi yaptığından tekrar emin olun, ve yalnızca değiştirmek istediğiniz kitapları seçin! Düzenli ifade arama kipinde, bir alanda arama yapabilirsiniz, metni başkasıyla değiştirebilirsiniz hatta sonucu başka bir alan yazabilirsiniz. Pratik bir örnek: Kitaplığınızın Frank Herbert’in Dune serisini içerdiğini düşünelim, Dune 1 - Dune, Dune 2 - Dune Messiah gibi isimlendirilmiş olsun. Şimdi seri alanına Dune getirmek istediğinizi düşünelim. Bunu başlık alanında (.*?) \d+ - .* arayarak ve seri alanında \1 ile değiştirerek yapabilirsiniz. Ne yaptığımı anladınız mı? Seri alanını ilk gruba referansla değiştiriyoruz. Şimdi serileri ayarladığınıza göre, yalnızca başlık alanında .*? - araması yapmak ve "" (boş karakter dizisi) ile değiştirmek kaldı. Harika değil mi? Bu arada, tüm alanı değiştirmek yerine, alanın başına ya da sonuna ekleme de yapabilirsiniz, böylece kitap başlığının önüne seri bilgisi getirmek isterseniz, bunu da yapabilirsiniz. Şimdiye kadar fark ettiğiniz üzere, Büyük küçük harf duyarlı olarak etiketlenmiş bir kontrol kutusu var, yani bu davranış için burada bayrak kullanmak zorunda değilsiniz.

Bu, düzenli ifadelere çok kısa giriş turumuzun sonu. Umarım en azından başlamanıza yetecek kadar ve kendi kendinize öğrenmeye devam edecek kadar şey anlatabilmişimdir- iyi bir başlangıç noktası Python düzenli ifade belgeleridir.

Son bir uyarı: Düzenli ifadeler güçlüdür, ama aynı zamanda yanlış anlaşılması oldukça kolaydır. calibre ifadelerinizi beklediğiniz gibi çalışıp çalışmadığını gösteren gerçekten güzel test imkanları sunar. Kullanın onları. Kendinizi ayağınızdan vurmayın. (Bu ifadeye bayılıyorum…) Ama bu uyarıya rağmen kendinizi vurursanız, bundan ders çıkarmaya çalışın.

Hazırlayanlar

İpuçları, düzeltmeler vs. için teşekkürler:

  • ldolse
  • kovidgoyal
  • chaley
  • dwanthny
  • kacir
  • Starson17
  • Orpheu

Düzenli ifadelerle ilgili fazlası için bknz Python Kullanıcı Kılavuzu.