Mod Fungsi untuk Gelintar & Ganti di dalam Penyunting¶
Alat Gelintar & Ganti dalam penyunting menyokong mod fungsi. Dalam mod ini, anda boleh gabungkan ungkapan nalar (rujuk Semua berkenaan penggunaan ungkapan nalar di dalam calibre) dengan fungsi hebat Python secara arbitrari untuk membuat semua bentuk pemprosesan teks lanjutan.
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.
Teknik penggunaan mod fungsi dan sintaks akan dijelaskan bersama-sama dengan contoh, memudahkan penjelasan bagaimana hendak cipta fungsi yang dapat melakukan tugas yang lebih kompleks.
Membaiki huruf (case) tajuk dokumen secara automatik¶
Di sini, kita akan guna salah satu fungsi terbina-dalam di dalam penyunting untuk mengubah huruf semua teks dalam tag tajuk menjadi title case iaitu huruf besar pertama dalam setiap perkataan:
Find expression: <([Hh][1-6])[^>]*>.+?</\1>
Untuk fungsi, hanya pilih fungsi terbina-dalam teks Title-case (abai tag). Ia akan mengubah tajuk menjadi seperti berikut: <h1>some TITLE</h1>
menjadi <h1>Some Title</h1>
. Ia masih berfungsi walaupun masih terdapat tag HTML lain di dalam tag pengepala.
Fungsi suai pertama anda - hypen pintar¶
Kehebatan mod fungsi sebenarnya berasal dari keupayaan mencipta fungsi anda sendiri untuk memproses teks mengikut kehendak sendiri. Alat Tanda Baca Pintar di dalam penyunting membolehkan tanda sempang ditinggalkan, supaya anda boleh guna fungsi ini untuk menggantikannya dengan tanda sengkang-em.
Untuk mencipta satu fungsi baharu, hanya klik butang Cipta/sunting untuk mencipta satu fungsi baharu dan salin kod Python dari bawah.
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 wont 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.
Guna fungsi ini dengan ungkapan nalar find:
>[^<>]+<
Dan ia akan gantikan semua tanda sengkang dengan sengkang-em, tetapi hanya dalam teks sebenar dan tidak di dalam takrifan tag HTML/
Kehebatan mod fungsi - menggunakan kamus ejaan untuk baiki perkataan tertinggal-sempang¶
Biasanya, e-buku dicipta dari imbasan buku bercetak yang menganfungi perkataan tertinggal-sempang -- perkataan yang mana dipisah pada akhir baris pada halaman bercetak. Kami akan hasilkan fungsi ringkas untuk cari dan baiki perkataan tersebut secara automatik.
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
Guna fungsi ini dengan ungkapan find yang sama sebelum ini, iaitu:
>[^<>]+<
Dan ia akan membaiki secara magik semua perkataan yang tiada-sempang dalam teks buku. Caranya adalah guna salah satu argumen tambahan untuk menggantikan fungsi, dictionaries
. Ini merujuk pada kamus penyunting itu sendiri menggunakan semakan ejaan teks di dalam buku tersebut. Fungsi ini mencari perkataan yang diasing dengan tanda sempang, buang tanda sempang tersebut dan periksa jika kamus mengenalpasti perkataan komposit itu, jika ada, perkataan asal akan digantikan dengan perkataan yang tidak menggunakan tanda sempang tersebut.
Perhatian satu kekangan bagi teknik ini adalah ia hanya berfungsi baik dengan buku satu bahasa, kerana, secara lalai, dictionaries.recognized()
menggunakan bahasa utama buku.
Seksyen pernomboran automatik¶
Sekarang kita dapati ada beberapa perkara berlainan. Anggaplah fail HTML anda mempunyai banyak seksyen, setiapnya dengan pengepala dengan <h2>
tag seperti <h2>Some text</h2>
. Anda boleh hasilkan fungsi suai yang dapat menomborkan pengepala ini dengan nombor seksyen yang berturuan, supaya ia kelihatan seperti <h2>1. Some text</h2>
.
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'
Guna ia dengan ungkapan cari:
(?s)(<h2[^<>]*>)(.+?</h2>)
Letak kursor di bahagian atas fail dan klik Ganti semua.
Fungsi ini menggunakan argumen tambahan yang berguna pada replace()
: argumen number
. Ketika membuat Replace All nombor secara automatik ditokok bagi setiap padanan yang berjaya.
Satu fitur baharu lain yang boleh digunakan ialah penggunaan replace.file_order
-- menetapkan 'spine'
bermaksud jika gelintar ini dijalankan pada fail HTML berbilang, fail diproses dengan tertib mengikut kemunculannya di dalam buku. Sila rujuk Pilih tertib fail bila dijalankan pada fail HTML berbilang untuk perinciannya.
Auto jana Senarai Kandungan¶
Akhir sekali, cuba lakukan yang lebih sukar. Anggap buku anda mempunyai pengepala dengan tag h1
dan h2
seperi <h1 id="someid">Some Text</h1>
. Kita akan auto-janakan Senarai Kandungan HTML berdasarkan pengeapala ini. Cipta fungsi suai seperti di bawah:
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'
Guna ia dengan ungkapan cari:
<(h[12]) [^<>]* id=['"]([^'"]+)['"][^<>]*>([^<>]+)
Jalankan penggelintaran pada All text files dan dipenghujung gelintar, satu tetingkap timbul dengan "Debug output from your function" yang mana akan mempunyai Senarai Kandungan HTML, sedia untuk ditampal ke dalam toc.html
.
Fungsi di atas boleh diberikan ulasan, supaya ia mudah diikuti. Fitur utama baharu ini ialah penggunaan argumen tambahan lain yang berguna pada fungsi replace()
, objek data
. Objek data
ialah dic Python yang berterusan diantara semua invokasi replace()
yang berjaya semasa satu operasi Replace All.
Lain-lain fitur baharu yang digunakan ialah call_after_last_match
-- menetapkannya True
pada fungsi replace()
bermaksud penyunting akan memanggil replace()
sekali laig selepas semua padanan telah ditemui. Untuk panggilan ekstra ini, objek padanan akan menjadi None
.
Ini hanyalah demonstrasi untuk menunjukkan kehebatan mod fungsi, jika anda perlu jana Senarai Kandungan dari pengepala dalam buku anda, anda digalakkan guna alat Senarai Kandungan yang disediakan dalam Alat → Senarai Kandungan.
API untuk mod fungsi¶
Semua fungsi mod fungsi mestilah fungsi Python yang bernama replace, dengan tandatangan berikut:
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):
return a_string
Bila cari/ganti dijalankan, bagi setiap padanan yang ditemui, fungsi replace()
akan dipanggilkan, ia mesti kembalikan rentetan penggantian untuk padanan tersebut. Jika tiada penggantian dibuat, ia seharusnya kembalikan match.group()
yang mana merupakan rentetan asal. Pelbagai dokumentasi argumen berkenaan fungsi replace()
seperti di bawah.
Argumen match
¶
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.
Argumen number
¶
Argumen number
ialah bilangan padanan semasa. Ketika anda menjalankan Ganti Semua, setiap padanan yang berjaya akan menyebabkan replace()
diganti dengan bilangan menaik. Padanan pertama mempunyai nilai 1.
Argumen file_name
¶
Ia merupaakn nama fail bagi fail yang mana padanan semasa ditemui. Ketika menggelintar di dalam teks bertanda, file_name
adalah kosong. file_name
adalah dalam bentuk canonical, iaitu laluan berkaitan dengan root buku, menggunakan /
sebagai pemisah laluan.
Argumen metadata
¶
Ia mewakili data meta bagi sesebuah buku, seperti tajuk, pengarang, bahasa, dll. Ia merupakan objek bagi sesebuah kelas calibre.ebooks.metadata.book.base.Metadata
. Atribut yang berguna termasuklah, title
, authors
(senarai pengarang) dan language
(kod bahasa).
Argumen dictionaries
¶
Ia mewakili koleksi kamus yang digunakan untuk penyemakan ejaan buku semasa. Merupakan kaedah paling berguna iaitu dictionaries.recognized(word)
yang akan kembalikan True
jika perkataan dikenalpasti oleh kamus bagi bahasa buku semasa.
Argumen data
¶
Ia merupakan dict
Python ringkas. Kitika anda menjalankan Ganti semua, setiap padanan berjaya akan menyebabkan replace()
dipanggil dengan dict
yang sama sebagai data. Maka anda boleh guna ia untuk menyimpan data arbitrari diantara penyeruan replace()
semasa operasi Ganti semua.
Argumen functions
¶
Argumen functions
memberikan anda capaian ke semua lain-lain fungsi ditakrif pengguna. Ia berguna untuk guna-semula kod. Anda boleh takrifkan fungsi utiliti dari satu tempat dan guna-semula ia dalam fungsi yang lain. Sebagai contoh, anggap anda menghasilkan satu fungsi bernama``My Function`` seperti di bawah:
def utility():
# do something
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):
...
Oleh itu, dalam fungsi lain, anda boleh boleh mencapai fungsi utility()
seperti ini:
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):
utility = functions['My Function']['utility']
...
Anda juga boleh menggunakan objek fungsi untuk menyimpan data tekal, yang boleh diguna-semula oleh fungsi lain. Sebagai contoh, anda boleh mempunyai satu fungsi yang mana bila dijalankan dengan Ganti Semua dapat mengutip beberapa data dan lain-lain fungsi yang menggunakannya jika ia dijalankan selepas itu. Pertimbangkan dua fungsi berikut:
# 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']
...
Meyahpepijat fungsi anda¶
Anda boleh menyahpepijat fungsi yang telah dicipta menggunakan fungsi piawai print()
daripada Python. Output print akan dipaparkan dalam tetingkap timbul selepas Find/replace telah selesai. Didapati terdapat contoh penggunaan print()
untuk outputkan keseluruhan jadual kandungan di atas.
Pilih tertib fail bila dijalankan pada fail HTML berbilang¶
Bila anda menjalankan Ganti semua pada fail HTML berbilang, tertib fail diproses bergantung pada apakah fail anda telah buka untuk penyuntingan. Anda boleh paksa menggelintar untuk proses fail mengikut tertib yang muncul berdasarkan tetapan atribut file_order
dalam fungsi anda, seperti berikut:
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):
...
replace.file_order = 'spine'
file_order
menerima dua nilai, spine
dan spine-reverse
yang menyebabkan gelintar memproses fail berbilang mengikut tertib muncul di dalam buku, sama ada maju atau mengundur.
Menambah masa tambahan ke dalam fungsi anda selepas padanan terakhir ditemui¶
Dalam senarai kandungan diauto-jana seperti ciontoh di atas, Lebih berguna anda menambah masa tambahan selepas padanan terakhir ditemui. Anda boleh membuatnya dengan menetapkan atribut call_after_last_match
ke dalam fungsi anda, seperti di bawah:
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):
...
replace.call_after_last_match = True
Menambah output dari fungsi ke teks betanda¶
Ketika menjalankan gelintar dan ganti pada teks bertanda, kadang kala berguna membuat penambahan di bahagian hujung teksd bertanda. Anda boleh membuatnya dengan menetapkan atribut append_final_output_to_marked
pada fungsi anda (perhatian anda juga perlu tetapkan call_after_last_match
), seperti berikut:
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
Memaksa dialog keputusan ketika membuat penggelintaran pada teks bertanda¶
Anda juga memaksa dialog keputusan (yang boleh memperlahankan aplikasi menggelintar/mengganti yang berulang pada kebanyakan blok teks) dengan menetapkan atribut suppress_result_dialog
pada fungsi anda, seperti ini:
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):
...
replace.suppress_result_dialog = True
Lagi banyak contoh¶
More useful examples, contributed by calibre users, can be found in the calibre E-book editor forum.