Function mode for Search & replace in the Editor¶
The Search & replace tool in the editor support a function mode. In this mode, you can combine regular expressions (see Calibre’de kurallı ifadelerin kullanımına dair her şey) with arbitrarily powerful Python functions to do all sorts of advanced text processing.
In the standard regexp mode for search and replace, you specify both a regular expression to search for as well as a template that is used to replace all found matches. In function mode, instead of using a fixed template, you specify an arbitrary function, in the Python programming language. This allows you to do lots of things that are not possible with simple templates.
Fonksiyon kipi ve söz dizimi kullanım teknikleri örneklerle açıklanacak, gittikçe zorlaşan görevleri fonksiyon kipiyle nasıl yapacağınız gösterilecektir.
Belgedeki başlık büyük küçük harflerinin otomatik düzeltilmesi¶
Burda, düzenleyicideki dahili fonksiyonlardan birini göz önüne alıp başlık etiketleri içindeki tüm metnin harflerini nasıl otomatik olarak başlık boyutuna değiştireceğimize bakacağız:
Find expression: <([Hh][1-6])[^>]*>.+?</\1>
For the function, simply choose the Title-case text (ignore tags) builtin
function. The will change titles that look like: <h1>some titLE</h1>
to
<h1>Some Title</h1>
. It will work even if there are other HTML tags inside
the heading tags.
İlk özel fonksiyonunuz - akıllı tireler¶
Fonksiyon kipinin asıl gücü metni keyfi şekillerde işlemenizi sağlayan kendi fonksiyonlarınızı yazabilmenizden gelir. Düzenleyicideki Akıllı Noktalama aracı bağımsız tirelere dokunmaz, yani bu fonksiyonu kullanarak onları uzun tirelerle değiştirebilirsiniz.
To create a new function, simply click the Create/edit button to create a new function and copy the Python code from below.
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):
return match.group().replace('--', '—').replace('-', '—')
Every Search & replace custom function must have a unique name and consist of a
Python function named replace, that accepts all the arguments shown above.
For the moment, we won’t worry about all the different arguments to
replace()
function. Just focus on the match
argument. It represents a
match when running a search and replace. Its full documentation in available
here.
match.group()
simply returns all the matched text and all we do is replace
hyphens in that text with em-dashes, first replacing double hyphens and
then single hyphens.
Bu fonksiyonu arama düzenli ifadesi ile kullanın:
>[^<>]+<
Tüm tireleri uzun tire ile değiştirecektir, ama yalnızca asıl metin içinde HTML etiket tanımlarında değil.
Fonksiyon kipinin gücü - yanlış tirelenmiş kelimeler için bir yazım denetim sözlüğü kullanmak¶
Often, e-books created from scans of printed books contain mis-hyphenated words – words that were split at the end of the line on the printed page. We will write a simple function to automatically find and fix such words.
import regex
from calibre import replace_entities
from calibre import prepare_string_for_xml
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):
def replace_word(wmatch):
# Try to remove the hyphen and replace the words if the resulting
# hyphen free word is recognized by the dictionary
without_hyphen = wmatch.group(1) + wmatch.group(2)
if dictionaries.recognized(without_hyphen):
return without_hyphen
return wmatch.group()
# Search for words split by a hyphen
text = replace_entities(match.group()[1:-1]) # Handle HTML entities like &
corrected = regex.sub(r'(\w+)\s*-\s*(\w+)', replace_word, text, flags=regex.VERSION1 | regex.UNICODE)
return '>%s<' % prepare_string_for_xml(corrected) # Put back required entities
Bu fonksiyonu aynı bulma ifadesi ile kullanın, açmak gerekirse:
>[^<>]+<
Böylece kitap metnindeki tüm yanlış tirelenmiş kelimeleri sihirli bir şekilde düzeltecektir. Ana nokta replace fonksiyonuna verilen kullanışlı bir ek bağımsız değişken olan dictionaries
. Bu düzenleyicinin kitap metninde yazım denetimi yaptığı sözlükleri kasteder. Bu fonksiyonun yaptığı ise bir tire ile ayrılmış kelimelere bakmak, tireyi kaldırmak ve karma kelimenin sözlük tarafından tanınıp tanınmadığına bakmaktır, eğer tanınıyorsa asıl kelimeler tire olmayan karma kelimelerle değiştirilir.
Bu tekniğin kısıtlarından biri yalnızca tek dilli kitaplarda çalışacak olmasıdır, çünkü var sayılan olarak, dictionaries.recognized()
kitabın ana dilini kullanır.
Kısımların otomatik numaralandırılması¶
Şimdi biraz daha farklı bir şey göreceğiz. HTML dosyanızın birçok kısmı olduğunu farz edin, her biri bir <h2>
etiketi içinde <h2>Bir metin</h2>
gibi görünen başlıkla. Özel bir fonksiyon oluşturup bu başlıkları otomatik olarak sıralı numaralar şeklinde numaralandırabilirsiniz, böylece <h2>1. Bir metin</h2>
olarak görünürler.
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):
section_number = '%d. ' % number
return match.group(1) + section_number + match.group(2)
# Ensure that when running over multiple files, the files are processed
# in the order in which they appear in the book
replace.file_order = 'spine'
Arama ifadesiyle birlikte kullanın:
(?s)(<h2[^<>]*>)(.+?</h2>)
İmleci dosyanın üstüne konumlandırın ve Hepsini değiştir tıklayın.
Bu fonksiyon replace()
fonksiyonuna ek başka kullanışlı bir bağımsız değişken kullanır: number
değişkeni. Hepsini değiştir yaparken sayı otomatik olarak her başarılı eşleşmede artırılır.
Yeni başka bir özellik replace.file_order
kullanımıdır – bunun 'spine'
olarak ayarlanması bu aramanın birden fazla HTML dosyada aranması durumunda, dosyaların kitapta bulundukları sırada işlenmesini anlamına gelir. Detaylar için bknz Çoklu HTML dosyalarında çalışırkenki dosya sırasını seç.
Otomatik olarak bir İçindekiler oluştur¶
Son olarak, biraz daha iddialı bir şey deneyelim. Kitabınızda <h1 id="birtakimid">Bir Metin</h1>
gibi görünen h1
ve h2
etiketli başlıklar olduğunu var sayın. Bu başlıklara dayalı bir İçindekileri otomatik olarak üreteceğiz. Aşağıdaki özel fonksiyonu oluşturun:
from calibre import replace_entities
from calibre.ebooks.oeb.polish.toc import TOC, toc_to_html
from calibre.gui2.tweak_book import current_container
from calibre.ebooks.oeb.base import xml2str
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):
if match is None:
# All matches found, output the resulting Table of Contents.
# The argument metadata is the metadata of the book being edited
if 'toc' in data:
toc = data['toc']
root = TOC()
for (file_name, tag_name, anchor, text) in toc:
parent = root.children[-1] if tag_name == 'h2' and root.children else root
parent.add(text, file_name, anchor)
toc = toc_to_html(root, current_container(), 'toc.html', 'Table of Contents for ' + metadata.title, metadata.language)
print(xml2str(toc))
else:
print('No headings to build ToC from found')
else:
# Add an entry corresponding to this match to the Table of Contents
if 'toc' not in data:
# The entries are stored in the data object, which will persist
# for all invocations of this function during a 'Replace All' operation
data['toc'] = []
tag_name, anchor, text = match.group(1), replace_entities(match.group(2)), replace_entities(match.group(3))
data['toc'].append((file_name, tag_name, anchor, text))
return match.group() # We don't want to make any actual changes, so return the original matched text
# Ensure that we are called once after the last match is found so we can
# output the ToC
replace.call_after_last_match = True
# Ensure that when running over multiple files, this function is called,
# the files are processed in the order in which they appear in the book
replace.file_order = 'spine'
Ve bulma ifadesiyle kullanın:
<(h[12]) [^<>]* id=['"]([^'"]+)['"][^<>]*>([^<>]+)
Run the search on All text files and at the end of the search, a
window will popup with “Debug output from your function” which will have the
HTML Table of Contents, ready to be pasted into toc.html
.
The function above is heavily commented, so it should be easy to follow. The
key new feature is the use of another useful extra argument to the
replace()
function, the data
object. The data
object is a Python
dictionary that persists between all successive invocations of replace()
during
a single Replace All operation.
Başka yeni bir özellik de call_after_last_match
kullanımıdır – bunu replace()
fonksiyonunda True
olarak ayarlamak düzenleyicinin tüm eşleşmeler bulunduktan sonra bir kere daha replace()
çağırması demektir. Bu ek çağrı için, eşleşme nesnesi None
olacaktır.
Bu yalnızca fonksiyon kipinin gücünü göstermek için bir gösteriydi, gerçekten bir kitaptaki başlıklardan İçindekiler oluşturmaya ihtiyacınız varsa, Araçlar → İçindekiler içindeki bu iş için atanmış İçindekiler aracını kullansanız daha iyi edersiniz.
Fonksiyon kipi için API¶
All function mode functions must be Python functions named replace, with the following signature:
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):
return a_string
Bir bul/değiştir çalıştığında, bulunan her eşleşme için, bu eşleşme için değiştirme karater dizisini döndürmesi gereken replace()
fonksiyonu çağrılacaktır. Herhangi bir değiştirme yapılmayacaksa, asıl karakter dizisi olan match.group()
döndürmelidir. replace()
fonksiyonuna verilen çeşitli bağımsız değişkenler aşağıda belgelenmiştir.
match
bağımsız değişkeni¶
The match
argument represents the currently found match. It is a
Python Match object.
Its most useful method is group()
which can be used to get the matched
text corresponding to individual capture groups in the search regular
expression.
number
bağımsız değişkeni¶
number
bağımsız değişkeni mevcut eşleşmenin sayısıdır. Hepsini Değiştir çalıştırdığınızda, her başarılı eşleşme ``replace()``in artan bir sayıyla çağrılmasına sebep olur. İlk eşleşmenin 1 numarası vardır.
file_name
bağımsız değişkeni¶
Mevcut eşleşmenin bulunduğu dosyanın dosya ismidir. İşaretli metin içinde arama yaparken, file_name
boştur. file_name
kuralsal biçimindedir, ayraç olarak /
kullanan kitabın köküne göreceli bir yol.
metadata
bağımsız değişkeni¶
Bu mevcut kitabın metadata’sını temsil eder, başlık, yazarlar, dil, vs. Bir calibre.ebooks.metadata.book.base.Metadata
nesnesidir. Kullanışlı öznitelikler arasında başlık
, yazarlar
(yazar listesi) ve dil
(dil kodu) bulunur.
dictionaries
bağımsız değişkeni¶
This represents the collection of dictionaries used for spell checking the
current book. Its most useful method is dictionaries.recognized(word)
which will return True
if the passed in word is recognized by the dictionary
for the current book’s language.
data
bağımsız değişkeni¶
This a simple Python dictionary
. When you run
Replace all, every successive match will cause replace()
to be
called with the same dictionary
as data. You can thus use it to store arbitrary
data between invocations of replace()
during a Replace all
operation.
functions
bağımsız değişkeni¶
functions
bağımsız değişkeni diğer tüm kullanıcı tanımlı fonksiyonlara erişim verir. Bu kod tekrar kullanımı için faydalıdır. Yardımcı fonksiyonları bir yerde tanımlayabilir ve diğer tüm fonksiyonlarınızda tekrar kullanabilirsiniz. Örneğin, şu şekilde My Function
isimli bir fonksiyon tanımladığınızı var sayalım:
def utility():
# do something
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):
...
Sonra, başka bir fonksiyon içinde, utility()
fonksiyonuna şu şekilde erişebilirsiniz:
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):
utility = functions['My Function']['utility']
...
Fonksiyonlar nesnesini diğer fonksiyonlarca tekrar kullanılabilen kalıcı veri depolamak için de kullanabilirsiniz. Örneğin, Hepsini Değiştir ile çağrıldığında veri toplayan bir fonksiyonunuz ve daha sonra çağrıldığında bunu kullanan ikinci bir fonksiyonunuz olabilir. Şu iki fonksiyonu göz önüne alın:
# Function One
persistent_data = {}
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):
...
persistent_data['something'] = 'some data'
# Function Two
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):
persistent_data = functions['Function One']['persistent_data']
...
Fonksiyonlarınızda hata ayıklama¶
You can debug the functions you create by using the standard print()
function from Python. The output of print will be displayed in a popup window
after the Find/replace has completed. You saw an example of using print()
to output an entire table of contents above.
Çoklu HTML dosyalarında çalışırkenki dosya sırasını seç¶
When you run a Replace all on multiple HTML files, the order in
which the files are processes depends on what files you have open for editing.
You can force the search to process files in the order in which the appear by
setting the file_order
attribute on your function, like this:
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):
...
replace.file_order = 'spine'
file_order
iki değer alır, aramanın birden çok dosyayı kitapta göründükleri sırada işlemesine sebep olan ve sırayla ileri veya geri anlamına gelen``spine`` ve spine-reverse
.
Fonksiyonunuzun son eşleşme bulunduktan sonra ek bir sefer daha çağrılması¶
Bazen, yukarıdaki içindekileri otomatik olarak üreten örnek gibi, son eşleşme bulunduktan sonra fonksiyonunuzu bir kere daha çağırmak faydalı olabilir. Bunu fonksiyonunuzda call_after_last_match
özniteliğini şu şekilde ayarlayarak yapabilirsiniz:
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):
...
replace.call_after_last_match = True
Appending the output from the function to marked text¶
When running search and replace on marked text, it is sometimes useful to
append so text to the end of the marked text. You can do that by setting
the append_final_output_to_marked
attribute on your function (note that you
also need to set call_after_last_match
), like this:
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):
...
return 'some text to append'
replace.call_after_last_match = True
replace.append_final_output_to_marked = True
Suppressing the result dialog when performing searches on marked text¶
You can also suppress the result dialog (which can slow down the repeated
application of a search/replace on many blocks of text) by setting
the suppress_result_dialog
attribute on your function, like this:
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):
...
replace.suppress_result_dialog = True
More examples¶
More useful examples, contributed by calibre users, can be found in the calibre E-book editor forum.