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. Finally, you can use regular expressions when searching the calibre book list and when searching inside the calibre E-book viewer.

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ı!

I was hoping you’d say that. But brace yourself, now it gets even better! We just saw that using sets, we could match one of several characters at once. But you can even repeat a character or set, reducing the number of expressions needed to handle the above page number example to one. Yes, ONE! Excited? You should be! It works like this: Some so-called special characters, “+”, “?” and “*”, repeat the single element preceding them. (Element means either a single character, a character set, an escape sequence or a group (we’ll learn about those last two later)- in short, any single entity in a regular expression). These characters are called wildcards or quantifiers. To be more precise, “?” matches 0 or 1 of the preceding element, “*” matches 0 or more of the preceding element and “+” matches 1 or more of the preceding element. A few examples: The expression a? would match either “” (which is the empty string, not strictly useful in this case) or “a”, the expression a* would match “”, “a”, “aa” or any number of a’s in a row, and, finally, the expression a+ would match “a”, “aa” or any number of a’s in a row (Note: it wouldn’t match the empty string!). Same deal for sets: The expression [0-9]+ would match every integer number there is! I know what you’re thinking, and you’re right: If you use that in the above case of matching page numbers, wouldn’t that be the single one expression to match all the page numbers? Yes, the expression Page [0-9]+ of 423 would match every page number in that book!

Not

A note on these quantifiers: They generally try to match as much text as possible, so be careful when using them. This is called “greedy behaviour”- I’m sure you get why. It gets problematic when you, say, try to match a tag. Consider, for example, the string "<p class="calibre2">Title here</p>" and let’s say you’d want to match the opening tag (the part between the first pair of angle brackets, a little more on tags later). You’d think that the expression <p.*> would match that tag, but actually, it matches the whole string! (The character “.” is another special character. It matches anything except linebreaks, so, basically, the expression .* would match any single line you can think of). Instead, try using <p.*?> which makes the quantifier "*" non-greedy. That expression would only match the first opening tag, as intended. There’s actually another way to accomplish this: The expression <p[^>]*> will match that same opening tag- you’ll see why after the next section. Just note that there quite frequently is more than one way to write a regular expression.

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?

Knew you’d ask. Some useful sets are [0-9] matching a single number, [a-z] matching a single lowercase letter, [A-Z] matching a single uppercase letter, [a-zA-Z] matching a single letter and [a-zA-Z0-9] matching a single letter or number. You can also use an escape sequence as shorthand:

\d

is equivalent to [0-9]

\w

is equivalent to [a-zA-Z0-9_]

\s

is equivalent to any whitespace

Not

“Whitespace” is a term for anything that won’t be printed. These characters include space, tabulator, line feed, form feed, carriage return, non-breaking spaces, etc.

Not

The upper and lower case sets may match both upper and lowercase if the setting to make searches case insensitive is enabled. Such settings are found, for instance in Preferences->Searching in calibre itself and on the Search panel in the calibre E-book viewer as well as the calibre Edit book tool.

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

The last part is regular expression Search and replace in metadata fields. You can access this by selecting multiple books in the library and using bulk metadata edit. Be very careful when using this last feature, as it can do Very Bad Things to your library! Doublecheck that your expressions do what you want them to using the test fields, and only mark the books you really want to change! In the regular expression search mode, you can search in one field, replace the text with something and even write the result into another field. A practical example: Say your library contained the books of Frank Herbert’s Dune series, named after the fashion Dune 1 - Dune, Dune 2 - Dune Messiah and so on. Now you want to get Dune into the series field. You can do that by searching for (.*?) \d+ - .* in the title field and replacing it with \1 in the series field. See what I did there? That’s a reference to the first group you’re replacing the series field with. Now that you have the series all set, you only need to do another search for .*? - in the title field and replace it with "" (an empty string), again in the title field, and your metadata is all neat and tidy. Isn’t that great? By the way, instead of replacing the entire field, you can also append or prepend to the field, so, if you wanted the book title to be prepended with series info, you could do that as well. As you by now have undoubtedly noticed, there’s a checkbox labeled Case sensitive, so you won’t have to use flags to select behaviour here.

Well, that just about concludes the very short introduction to regular expressions. Hopefully I’ll have shown you enough to at least get you started and to enable you to continue learning by yourself- a good starting point would be the Python documentation for regexps.

One last word of warning, though: Regexps are powerful, but also really easy to get wrong. calibre provides really great testing possibilities to see if your expressions behave as you expect them to. Use them. Try not to shoot yourself in the foot. (God, I love that expression…). But should you, despite the warning, injure your foot (or any other body parts), try to learn from it.

Quick reference

Hazırlayanlar

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

  • ldolse

  • kovidgoyal

  • chaley

  • dwanthny

  • kacir

  • Starson17

  • Orpheu

For more about regexps see The Python User Manual. The actual regular expression library used by calibre is: regex which supports several useful enhancements over the Python standard library one.