calibre 模板语言

calibre模板语言是calibre特定的语言,用于在calibre中执行任务,例如指定文件路径、格式化值和计算用户指定列的值。示例:

  • 在将文件从calibre书库保存到磁盘或电子书阅读器时,指定文件夹结构和文件名。

  • 定义规则以将图标和颜色添加到calibre图书列表中。

  • 定义包含来自其他列的数据的“虚拟列”。

  • 高级书库搜索。

  • 高级元数据搜索和替换。

该语言是围绕“模板”的概念构建的,它指定要使用的图书元数据、元数据的计算以及如何格式化。

基本模板

基本模板由一个或多个“模板表达式”组成。 “模板表达式”由大括号 (“{}”) 中的文本和名称组成,并由正在处理的书籍中的相应元数据替换。 例如,calibre 中用于将书籍保存到设备的默认模板有 4 个“模板表达式”:

{author_sort}/{title}/{title} - {authors}

对于“艾萨克·阿西莫夫”所著的《基础》一书,将变为:

Asimov, Isaac/The Foundation/The Foundation - Isaac Asimov

斜杠不是“模板表达式”,因为它们位于“{}”之间。 此类文本保留在其出现的位置。 例如,如果模板是:

{author_sort} Some Important Text {title}/{title} - {authors}

那么对于“The Foundation”,模板会生成:

Asimov, Isaac Some Important Text The Foundation/The Foundation - Isaac Asimov

“模板表达式”可以通过使用列的“查找名称”来访问 calibre 中可用的所有元数据,包括自定义列(您自己创建的列)。 要查找“列”(有时称为“字段”)的查找名称,请将鼠标悬停在 calibre 图书列表中的列标题上。 自定义列的查找名称始终以“#”开头。 对于系列类型列,有一个名为“#lookup name_index”的附加字段,它是该系列中该书的系列索引。 例如,如果您有一个名为“#myseries”的自定义系列列,那么还将有一个名为“#myseries_index”的列。 标准系列列的索引名为“series_index”。

除了基于标准列的字段之外,您还可以使用:

  • {formats} - calibre 书库中书籍可用的格式列表

  • {identifiers:select(isbn)} - 书籍的 ISBN

If the metadata for the field for a given book is not defined then the field in the template is replaced by the empty string (''). For example, consider the following template:

{author_sort}/{series}/{title} {series_index}

If Asimov’s book “Second Foundation” is in the series “Foundation” then the template produces:

Asimov, Isaac/Foundation/Second Foundation 3

If a series has not been entered for the book then the template produces:

Asimov, Isaac/Second Foundation

The template processor automatically removes multiple slashes and leading or trailing spaces.

高级格式

In addition to metadata substitution, templates can conditionally include additional text and control how substituted data is formatted.

Conditionally including text

有时,您希望仅当字段不为空时文本才出现在输出中。 常见的情况是“series”和“series_index”,其中您不需要任何内容或用连字符分隔两个值。 calibre 使用特殊的“模板表达式”语法来处理这种情况。

For example and using the above Foundation example, assume you want the template to produce Foundation - 3 - Second Foundation. This template produces that output:

{series} - {series_index} - {title}

但是,如果一本书没有系列,模板将生成“- - 标题”,这可能不是您想要的。 一般来说,人们希望结果是没有无关连字符的标题。 您可以使用以下模板语法来完成此操作:

{field:|prefix_text|suffix_text}

这个“模板表达式”表示,如果“field”的值为“XXXX”,那么结果将为“prefix_textXXXXXsuffix_text”。 如果“field”为空(没有值),那么结果将是空字符串(什么也没有),因为前缀和后缀被忽略。 前缀和后缀可以包含空格。

Do not use subtemplates (`{ … }`) or functions (see below) in the prefix or the suffix.

Using this syntax, we can solve the above no-series problem with the template:

{series}{series_index:| - | - }{title}

仅当该书具有系列索引时才会包含连字符,而该索引仅当它具有系列时才包含。 再次继续 Foundation 示例,模板将生成“Foundation - 1 - Second Foundation”。

Notes:

  • You must include the colon after the lookup name if you are using a prefix or a suffix.

  • You must either use either no or both | characters. Using one, as in {field:| - }, is not allowed.

  • It is OK to provide no text for either the prefix or the suffix, such as in {series:|| - }. The template {title:||} is the same as {title}.

Formatting

Suppose you want the series_index to be formatted as three digits with leading zeros. This does the trick:

{series_index:0>3s} - Three digits with leading zeros

For trailing zeros, use:

{series_index:0<3s} - Three digits with trailing zeros

如果您使用带有小数值的系列索引,例如 1.1,您可能希望小数点对齐。 例如,您可能希望索引 1 和 2.5 显示为 01.00 和 02.50,以便它们在进行词法排序的设备上正确排序。 为此,请使用:

{series_index:0>5.2f} - Five characters consisting of two digits with leading zeros, a decimal point, then 2 digits after the decimal point.

If you want only the first two letters of the data, use:

{author_sort:.2} - Only the first two letters of the author sort name

大部分 calibre 模板语言格式都来自 Python。 有关这些高级格式化操作的语法的更多详细信息,请参阅“Python 文档 <https://docs.python.org/3/library/string.html#formatstrings>”_。

Using templates to define custom columns

模板可用于显示 calibre 元数据中没有的信息,或以不同于 calibre 正常格式的方式显示元数据。 例如,您可能想要显示“ISBN”,这是 calibre 不显示的字段。 您可以通过创建类型为“从其他列构建的列”(以下称为“复合列”)的自定义列来完成此操作,并提供一个模板来生成显示的文本。 该列将显示评估模板的结果。 例如,要显示 ISBN,请创建列并在模板框中输入“{identifiers:select(isbn)}”。 要显示包含两个系列自定义列的值(以逗号分隔)的列,请使用``{#series1:||,}{#series2}``。

Composite columns can use any template option, including formatting.

注意:您无法编辑复合列中显示的数据。 相反,您可以编辑源列。 如果您编辑复合列,例如通过双击它,calibre 将打开模板进行编辑,而不是基础数据。

Templates and plugboards

插件板用于在发送到设备和保存到磁盘操作期间更改写入书籍的元数据。 插件板允许您指定一个模板来提供要写入书籍元数据的数据。 您可以使用插件板修改以下字段:作者、author_sort、语言、出版商、标签、书名、title_sort。 此功能可以帮助想要在设备上使用图书中的不同元数据的人们解决排序或显示问题。

创建插接板时,您可以指定插接板要使用的格式和设备。 提供了一个特殊的设备“save_to_disk”,在保存格式时使用(而不是将它们发送到设备)。 选择格式和设备后,您可以选择要更改的元数据字段,并提供模板来提供新值。 这些模板“连接”到其目标字段,因此称为“插件板”。 您当然可以在这些模板中使用复合列。

Plugboards are quite flexible and can be written in Single Function Mode, Template Program Mode, General Program Mode, or Python Template mode.

当插件板可能适用时(内容服务器、保存到磁盘或发送到设备),calibre 会搜索定义的插件板,为给定的格式和设备选择正确的插件板。 例如,要为发送到 ANDROID 设备的 EPUB 图书找到合适的插件板,calibre 使用以下搜索顺序搜索插件板:

  • a plugboard with an exact match on format and device, e.g., EPUB and ANDROID

  • a plugboard with an exact match on format and the special any device choice, e.g., EPUB and any device

  • a plugboard with the special any format choice and an exact match on device, e.g., any format and ANDROID

  • a plugboard with any format and any device

标签和作者字段有特殊处理,因为这两个字段都可以容纳多个项目。 一本书可以有多个标签和多个作者。 当您指定要更改这两个字段之一时,将检查模板的结果以查看是否存在多个项目。 对于标签,只要 calibre 找到逗号,结果就会被分割。 例如,如果模板生成值“Thriller, Horror”,则结果将是两个标签“Thriller”和“Horror”。 无法在标签中间放置逗号。

作者也会发生同样的情况,但使用不同的字符进行剪切,即“&”(与号)而不是逗号。 例如,如果模板生成值“Blogs, Joe&Posts, Susan”,则该书最终将有两个作者:“Blogs, Joe”和“Posts, Susan”。 如果模板生成值“博客,乔;帖子,苏珊”,那么这本书将有一位作者的名字相当奇怪。

当将书籍保存到磁盘或写入设备时,插件板会影响写入书中的元数据。 插件板不会影响“保存到磁盘”和“发送到设备”用来创建文件名的元数据。 相反,文件名是使用在适当的首选项窗口中输入的模板构建的。

Using functions in templates - Single Function Mode

假设您想要以大写形式显示某个字段的值,而该字段通常为标题大写形式。 您可以使用“模板函数”来完成此操作。 例如,要以大写形式显示标题,请使用“uppercase”函数,如“{title:uppercase()}”。 要以标题大小写显示它,请使用``{title:titlecase()}``。

函数进入模板的格式部分,在 : 之后和第一个 | 之前,或者如果没有使用前缀/后缀,则在结束的 } 之前。 如果您同时具有格式和函数引用,则该函数位于第二个 : 后面。 函数返回模板中指定的列的值,经过适当修改。

The syntax for using functions is one of:

{lookup_name:function(arguments)}
{lookup_name:format:function(arguments)}
{lookup_name:function(arguments)|prefix|suffix}
{lookup_name:format:function(arguments)|prefix|suffix}

函数名称后面必须始终跟有左括号和右括号。 有些函数需要额外的值(参数),这些值位于括号内。 参数之间用逗号分隔。 文字逗号(逗号作为文本,而不是参数分隔符)前面必须有反斜杠 (\) 。 最后一个(或唯一的)参数不能包含文本右括号。

Functions are evaluated before format specifications and the prefix/suffix. See further down for an example of using both a format and a function.

重要:如果您有编程经验,请注意“单函数模式”中的语法不是您所期望的。 字符串不加引号,并且空格很重要。 所有参数都被视为常量; 没有表达式。

Do not use subtemplates (`{ … }`) as function arguments. Instead, use Template Program Mode and General Program Mode.

Some functions require regular expressions. In the template language regular expression matching is case-insensitive.

在下面的函数文档中,符号“[something]*”意味着“something”可以重复零次或多次。 符号“[something]+”表示“something”重复一次或多次(必须至少存在一次)。

The functions intended for use in Single Function Mode are:

  • capitalize() – returns the value with the first letter upper case and the rest lower case.

  • contains(pattern, text if match, text if not match) – checks if the value is matched by the regular expression pattern. Returns text if match if the pattern matches the value, otherwise returns text if no match.

  • count(separator) – 将值解释为由``separator`` 分隔的项目列表,并返回列表中的项目数。 大多数列表使用逗号作为分隔符,但“作者”使用与号(&)。 示例:{tags:count(,)}{authors:count(&)}。 别名:“count()”、“list_count()”

  • format_number(template) – 将值解释为数字,并使用 Python 格式模板,例如 {0:5.2f}{0:,d} 或 ` ${0:5,.2f}`。 格式化模板必须以“{0:”开头并以“}”结尾,如上面的示例所示。 例外:如果格式模板仅包含格式,则可以省略前导“{0:”和尾随“}”。 有关更多示例,请参阅模板语言和“Python 文档 <https://docs.python.org/3/library/string.html#formatstrings>`_”。 如果格式化失败,则返回空字符串。

  • human_readable() – expects the value to be a number and returns a string representing that number in KB, MB, GB, etc.

  • ifempty(text if empty) – if the value is not empty then return the value of the field, otherwise return text if empty.

  • in_list(separator, [pattern,found_val,]* not_found_val) – 将值解释为由``separator`` 分隔的项目列表,并对照列表中的每个项目检查``pattern``。 如果“pattern”与某个项目匹配,则返回“found_val”,否则返回“not_found_val”。 patternfound_value 对可以根据需要重复多次,允许根据项目的值返回不同的值。 按顺序检查模式,并返回第一个匹配项。

  • language_strings(localize) – 返回 语言代码 的`语言名称 <https:// www.loc.gov/standards/iso639-2/php/code_list.php>`_ 作为值传入。 示例:“{语言:语言字符串()}”。 如果“localize”为零,则返回英文字符串。 如果“localize”不为零,则返回当前语言环境的字符串。 Lang_codes 是一个以逗号分隔的列表。

  • list_item(index,separator) – 将值解释为由``separator`` 分隔的项目列表,返回第 ‘index’ 项。 第一项的编号为零。 最后一项的索引为“-1”,如“list_item(-1,separator)”中所示。 如果该项目不在列表中,则返回空字符串。

  • lookup([pattern, key, ]* else_key) – 将按顺序对照值检查模式。 如果模式匹配,则返回由“key”命名的字段的值。 如果没有模式匹配,则返回由“else_key”命名的字段的值。 请参阅``switch``(如下)。

  • lowercase() – returns the value of the field in lower case.

  • rating_to_stars(use_half_stars) – Returns the rating as string of star () characters. The value must be a number between 0 and 5. Set use_half_stars to 1 if you want half star characters for fractional numbers available with custom ratings columns.

  • re(pattern, replacement) – return the value after applying the regular expression. All instances of pattern in the value are replaced with replacement. The template language uses case insensitive Python regular expressions.

  • select(key) – 将值解释为以逗号分隔的项目列表,每个项目的形式为``id:value`` (calibre程序``identifier`` 格式)。 该函数查找 id 等于 key 的第一对并返回相应的值。 如果没有 id 匹配,则该函数返回空字符串。

  • shorten(left chars, middle text, right chars) – 返回值的缩短版本,由值开头的 left chars 字符组成,后跟 middle text, 后跟值末尾的“right chars”字符。 “左字符”和“右字符”必须是非负整数。 示例:假设您要显示的标题长度最多为 15 个字符。 执行此操作的一个模板是“{title:shorten(9,-,5)}”。 对于标题为“艾芬豪时代的古代英国法律”的书,结果将是“Ancient E-anhoe”:标题的前 9 个字符,“-”,然后是最后 5 个字符。 如果值的长度小于“左字符”+“右字符”+“中间文本”的长度,则该值将按原样返回。 例如,标题“The Dome”不会改变。

  • str_in_list(separator, [ string,found_val, ]+ not_found_val) – 将值解释为由``separator`` 分隔的项目列表,然后将``string`` 与列表中的每个值进行比较。 “string”不是正则表达式。 如果“string”等于任何项(忽略大小写),则返回相应的“found_val”。 如果“string”包含“separators”,那么它也被视为一个列表,并且每个子值都会被检查。 “string”和“found_value”对可以根据需要重复多次,允许根据字符串的值返回不同的值。 如果没有任何字符串匹配,则返回“not_found_value”。 按顺序检查字符串。 返回第一个匹配项。

  • subitems(start_index, end_index) – 此函数分解类似标签的分层项目列表,例如流派。 它将值解释为以逗号分隔的类似标记的项目列表,其中每个项目都是以句点分隔的列表。 它返回一个新列表,该列表是通过从每个项目中提取从“start_index”到“end_index”的组件,然后将结果合并在一起而形成的。 重复项被删除。 以句点分隔的列表中的第一个子项的索引为零。 如果索引为负数,则从列表末尾开始计数。 作为一种特殊情况,假设 end_index 为零是列表的长度。

    例如:

    • Assuming a #genre column containing A.B.C:

      • {#genre:subitems(0,1)} returns “A”

      • {#genre:subitems(0,2)} returns “A.B”

      • {#genre:subitems(1,0)} returns “B.C”

    • Assuming a #genre column containing “A.B.C, D.E”:

      • {#genre:subitems(0,1)} returns “A, D”

      • {#genre:subitems(0,2)} returns “A.B, D.E”

  • sublist(start_index,end_index,separator) – 将值解释为由``separator``分隔的项目列表,返回由``start_index``到``end_index``的项目组成的新列表 。 第一项的编号为零。 如果索引为负数,则从列表末尾开始计数。 作为一种特殊情况,假设 end_index 为零是列表的长度。

    Examples assuming that the tags column (which is comma-separated) contains “A, B ,C”:

    • {tags:sublist(0,1,\,)} returns “A”

    • {tags:sublist(-1,0,\,)} returns “C”

    • {tags:sublist(0,-1,\,)} returns “A, B”

  • swap_around_articles(separator) – 返回文章移至末尾的值。 该值可以是一个列表,在这种情况下,列表中的每个项目都会被处理。 如果该值是一个列表,那么您必须提供“分隔符”。 如果未提供“separator”,则该值将被视为单个值,而不是列表。 “articles”是 calibre 用于生成“title_sort”的内容。

  • swap_around_comma() – given a value of the form B, A, return A B. This is most useful for converting names in LN, FN format to FN LN. If there is no comma in the value then the function returns the value unchanged.

  • switch([pattern, value,]+ else_value) – 对于每个``pattern, value`` 对,检查该值是否与正则表达式``pattern`` 匹配,如果匹配则返回关联的``value’ ``。 如果没有“pattern”匹配,则返回“else_value”。 您可以根据需要拥有任意数量的“模式、值”对。 返回第一个匹配项。

  • test(text if not empty, text if empty) – return text if not empty if the value is not empty, otherwise return text if empty.

  • titlecase() – returns the value of the field in title case.

  • transliterate() – Return a string in a latin alphabet formed by approximating the sound of the words in the source field. For example, if the source field is Фёдор Миха́йлович Достоевский this function returns Fiodor Mikhailovich Dostoievskii.

  • uppercase() – returns the value of the field in upper case.

Using functions and formatting in the same template

假设您有一个整数自定义列“#myint”,您希望显示前导零,如“003”。 实现此目的的一种方法是使用“0>3s”的格式。 但是,默认情况下,如果数字(整数或浮点数)等于零,则该值将显示为空字符串,因此零值将生成空字符串,而不是“000”。 如果您想查看“000”值,则可以使用格式字符串和“ifempty”函数将空值更改回零。 模板将是:

{#myint:0>3s:ifempty(0)}

Note that you can use the prefix and suffix as well. If you want the number to appear as [003] or [000], then use the template:

{#myint:0>3s:ifempty(0)|[|]}

General Program Mode

General Program Mode (GPM) replaces template expressions with a program written in the template language. The syntax of the language is defined by the following grammar:

program         ::= 'program:' expression_list
expression_list ::= top_expression [ ';' top_expression ]*
top_expression  ::= or_expression
or_expression   ::= and_expression [ '||' and_expression ]*
and_expression  ::= not_expression [ '&&' not_expression ]*
not_expression  ::= [ '!' not_expression ]* | concatenate_expr
concatenate_expr::= compare_expr [ '&' compare_expr ]*
compare_expr    ::= add_sub_expr [ compare_op add_sub_expr ]
compare_op      ::= '==' | '!=' | '>=' | '>' | '<=' | '<' | 'in' | 'inlist' |
                    '==#' | '!=#' | '>=#' | '>#' | '<=#' | '<#'
add_sub_expr    ::= times_div_expr [ add_sub_op times_div_expr ]*
add_sub_op      ::= '+' | '-'
times_div_expr  ::= unary_op_expr [ times_div_op unary_op_expr ]*
times_div_op    ::= '*' | '/'
unary_op_expr   ::= [ add_sub_op unary_op_expr ]* | expression
expression      ::= identifier | constant | function | assignment | field_reference |
                    if_expr | for_expr | break_expr | continue_expr |
                    '(' expression_list ')' | function_def
field_reference ::= '$' [ '$' ] [ '#' ] identifier
identifier      ::= id_start [ id_rest ]*
id_start        ::= letter | underscore
id_rest         ::= id_start | digit
constant        ::= " string " | ' string ' | number
function        ::= identifier '(' expression_list [ ',' expression_list ]* ')'
function_def    ::= 'def' identifier '(' top_expression [ ',' top_expression ]* ')' ':'
                    expression_list 'fed'
assignment      ::= identifier '=' top_expression
if_expr         ::= 'if' condition 'then' expression_list
                    [ elif_expr ] [ 'else' expression_list ] 'fi'
condition       ::= top_expression
elif_expr       ::= 'elif' condition 'then' expression_list elif_expr | ''
for_expr        ::= for_list | for_range
for_list        ::= 'for' identifier 'in' list_expr
                    [ 'separator' separator_expr ] ':' expression_list 'rof'
for_range       ::= 'for' identifier 'in' range_expr ':' expression_list 'rof'
range_expr      ::= 'range' '(' [ start_expr ',' ] stop_expr
                    [ ',' step_expr [ ',' limit_expr ] ] ')'
list_expr       ::= top_expression
break_expr      ::= 'break'
continue_expr   ::= 'continue'
separator_expr  ::= top_expression
start_expr      ::= top_expression
stop_expr       ::= top_expression
step_expr       ::= top_expression
limit_expr      ::= top_expression

Notes:

  • a top_expression always has a value. The value of an expression_list is the value of the last top_expression in the list. For example, the value of the expression list 1;2;'foobar';3 is 3.

  • In a logical context, any non-empty value is True

  • In a logical context, the empty value is False

  • Strings and numbers can be used interchangeably. For example, 10 and '10' are the same thing.

  • Comments are lines starting with a ‘#’ character. Comments beginning later in a line are not supported.

Operator precedence

The operator precedence (order of evaluation) from highest (evaluated first) to lowest (evaluated last) is:

  • Function calls, constants, parenthesized expressions, statement expressions, assignment expressions, field references.

  • Unary plus (+) and minus (-). These operators evaluate right to left.

    These and all the other arithmetic operators return integers if the expression results in a fractional part equal to zero. For example, if an expression returns 3.0 it is changed to 3.

  • Multiply (*) and divide (/). These operators are associative and evaluate left to right. Use parentheses if you want to change the order of evaluation.

  • Add (+) and subtract (-). These operators are associative and evaluate left to right.

  • Numeric and string comparisons. These operators return '1' if the comparison succeeds, otherwise the empty string (''). Comparisons are not associative: a < b < c is a syntax error.

  • String concatenation (&). The & operator returns a string formed by concatenating the left-hand and right-hand expressions. Example: 'aaa' & 'bbb' returns 'aaabbb'. The operator is associative and evaluates left to right.

  • Unary logical not (!). This operator returns '1' if the expression is False (evaluates to the empty string), otherwise ''.

  • Logical and (&&). This operator returns ‘1’ if both the left-hand and right-hand expressions are True, or the empty string '' if either is False. It is associative, evaluates left to right, and does short-circuiting.

  • 逻辑或 (||)。 如果左侧表达式或右侧表达式为 True,则此运算符返回 '1';如果均为 False,则返回 ''。 它是关联的,从左到右求值,并进行“短路”<https://chortle.ccsu.edu/java5/Notes/chap40/ch40_2.html>`_。 它是一个“包含或”,如果左侧和右侧表达式都为 True,则返回“’1””。

Field references

A field_reference evaluates to the value of the metadata field named by lookup name that follows the $ or $$. Using $ is equivalent to using the field() function. Using $$ is equivalent to using the raw_field function. Examples:

* $authors ==> field('authors')
* $#genre ==> field('#genre')
* $$pubdate ==> raw_field('pubdate')
* $$#my_int ==> raw_field('#my_int')

If expressions

If 表达式首先评估``condition``。 如果“condition”为 True(非空值),则评估“then”子句中的“expression_list”。 如果为 False,则评估“elif”或“else”子句中的“expression_list”。 elifelse 部分是可选的。 单词“if”、“then”、“elif”、“else”和“fi”被保留; 您不能将它们用作标识符名称。 您可以在任何有意义的地方放置换行符和空格。 “condition”是“top_expression”,而不是“expression_list”; 不允许使用分号。 “表达式列表”是以分号分隔的“top_表达式”序列。 if 表达式返回已计算的 expression_list 中最后一个 top_expression 的结果,如果没有计算表达式列表,则返回空字符串。

Examples:

* program: if field('series') then 'yes' else 'no' fi
* program:
      if field('series') then
          a = 'yes';
          b = 'no'
      else
          a = 'no';
          b = 'yes'
      fi;
      strcat(a, '-', b)

Nested if example:

program:
  if field('series') then
    if check_yes_no(field('#mybool'), '', '', '1') then
      'yes'
    else
      'no'
    fi
  else
    'no series'
  fi

As said above, an if produces a value. This means that all the following are equivalent:

* program: if field('series') then 'foo' else 'bar' fi
* program: if field('series') then a = 'foo' else a = 'bar' fi; a
* program: a = if field('series') then 'foo' else 'bar' fi; a

As a last example, this program returns the value of the series column if the book has a series, otherwise the value of the title column:

program: field(if field('series') then 'series' else 'title' fi)

For expressions

for 表达式迭代一系列值,一次处理一个值。 “list_expression” 必须计算为元数据字段“查找名称”,例如“tags” 或“#genre”,或者计算为值列表。 `range() 函数 1`(见下文)生成一个数字列表。 如果结果是有效的“查找名称”,则将获取字段的值并使用为该字段类型指定的分隔符。 如果结果不是有效的查找名称,则假定它是值列表。 除非提供可选关键字“separator”,否则假定列表以逗号分隔,在这种情况下,列表值必须由评估“separator_expr”的结果分隔。 如果列表是由“range()”生成的,则不能使用分隔符。 列表中的每个值都分配给指定的变量,然后计算“表达式列表”。 您可以使用“break”跳出循环,并使用“continue”跳到循环的开头进行下一次迭代。

Example: This template removes the first hierarchical name for each value in Genre (#genre), constructing a list with the new names:

program:
  new_tags = '';
  for i in '#genre':
    j = re(i, '^.*?\.(.*)$', '\1');
    new_tags = list_union(new_tags, j, ',')
  rof;
  new_tags

如果原始类型是“History.Military, Science Fiction.Alternate History, ReadMe”,则模板将返回“Military, Alternate History, ReadMe”。 您可以在 calibre 的“批量编辑元数据 -> 搜索和替换”中使用此模板,并将“搜索”设置为“模板”,以剥离层次结构的第一级并将结果值分配给类型。

注意:在这种情况下,模板中的最后一行“new_tags”并不是绝对必要的,因为“for”返回表达式列表中最后一个 top_expression 的值。 赋值的值是其表达式的值,因此“for”语句的值就是分配给“new_tags”的值。

Function definition

If you have code in a template that repeats then you can put that code into a local function. The def keyword starts the definition. It is followed by the function name, the argument list, then the code in the function. The function definition ends with the fed keyword.

参数是立场性的。 调用函数时,提供的参数会从左到右与定义的参数进行匹配,并将参数的值分配给参数。 提供的参数多于定义的参数是错误的。 参数可以有默认值,例如“a = 25”。 如果没有为该参数提供参数,则使用默认值,否则该参数将设置为空字符串。

The return statement can be used in a local function.

A function must be defined before it can be used.

Example: This template computes an approximate duration in years, months, and days from a number of days. The function to_plural() formats the computed values. Note that the example also uses the & operator:

program:
      days = 2112;
      years = floor(days/360);
      months = floor(mod(days, 360)/30);
      days = days - ((years*360) + (months * 30));

      def to_plural(v, str):
              if v == 0 then return '' fi;
              return v & ' ' & (if v == 1 then str else str & 's' fi) & ' '
      fed;

      to_plural(years, 'year') & to_plural(months, 'month') & to_plural(days,'day')

Relational operators

Relational operators return '1' if the comparison is true, otherwise the empty string (‘’).

There are two forms of relational operators: string comparisons and numeric comparisons.

字符串比较使用词法顺序进行不区分大小写的字符串比较。 支持的字符串比较运算符有 ==!=<<=>>=in ` 和 inlist。 对于“in”运算符,左侧表达式的结果被解释为正则表达式模式。 如果左侧正则表达式的值与右侧表达式的值匹配,则“in”运算符为 True。 如果左侧正则表达式与右侧列表中的任何一项匹配,其中列表中的项目以逗号分隔,则“inlist”运算符为 true。 匹配不区分大小写。

The numeric comparison operators are ==#, !=#, <#, <=#, >#, >=#. The left and right expressions must evaluate to numeric values with two exceptions: both the string value “None” (undefined field) and the empty string evaluate to the value zero.

例如:

  • program: field('series') == 'foo' returns '1' if the book’s series is ‘foo’, otherwise ''.

  • program: 'f.o' in field('series') returns '1' if the book’s series matches the regular expression f.o (e.g., foo, Off Onyx, etc.), otherwise ''.

  • program: 'science' inlist field('#genre') returns '1' if any of the book’s genres match the regular expression science, e.g., Science, History of Science, Science Fiction etc., otherwise ''.

  • program: '^science$' inlist field('#genre') returns '1' if any of the book’s genres exactly match the regular expression ^science$, e.g., Science. The genres History of Science and Science Fiction don’t match. If there isn’t a match then returns ''.

  • program: if field('series') != 'foo' then 'bar' else 'mumble' fi returns 'bar' if the book’s series is not foo. Otherwise it returns 'mumble'.

  • program: if field('series') == 'foo' || field('series') == '1632' then 'yes' else 'no' fi returns 'yes' if series is either 'foo' or '1632', otherwise 'no'.

  • program: if '^(foo|1632)$' in field('series') then 'yes' else 'no' fi returns 'yes' if series is either 'foo' or '1632', otherwise 'no'.

  • program: if 11 > 2 then 'yes' else 'no' fi returns 'no' because the > operator does a lexical comparison.

  • program: if 11 ># 2 then 'yes' else 'no' fi returns 'yes' because the ># operator does a numeric comparison.

Additional available functions

The following functions are available in addition to those described in Single Function Mode.

In GPM the functions described in Single Function Mode all require an additional first parameter specifying the value to operate upon. All parameters are expression_lists (see the grammar above).

  • add(x [, y]*) – returns the sum of its arguments. Throws an exception if an argument is not a number. In most cases you can use the + operator instead of this function.

  • and(value [, value]*) – 如果所有值都不为空,则返回字符串“1”,否则返回空字符串。 您可以拥有任意多个值。 在大多数情况下,您可以使用“&&”运算符来代替此函数。 不将“and”替换为“&&”的原因之一是短路是否会因副作用而改变结果。 例如,“and(a=’’,b=5)”将始终执行两个赋值操作,而“&&”运算符不会执行第二个操作。

  • assign(id, val) – assigns val to id, then returns val. id must be an identifier, not an expression. In most cases you can use the = operator instead of this function.

  • approximate_formats() – 返回与书籍关联的以逗号分隔的格式列表。 尽管可能是正确的,但不能保证该列表是正确的。 可以使用模板``{:’approximate_formats()’}`` 在模板程序模式(见下文)中调用此函数和其他零参数函数。 请注意,生成的格式名称始终为大写,如 EPUB 中那样。 “approximate_formats()”函数比下面讨论的“formats_…”函数要快得多。

  • author_links(val_separator, pair_separator) – returns a string containing a list of authors and those authors’ link values in the form:

    author1 val_separator author1_link pair_separator author2 val_separator author2_link etc.
    

    作者与其链接值由“val_separator”字符串分隔,不添加空格。 “author:linkvalue” 对由 “pair_separator” 字符串参数分隔,不添加空格。 您可以选择不出现在作者姓名或链接中的分隔符字符串。 即使作者链接为空,也会包含作者。

  • author_sorts(val_separator) – 返回一个字符串,其中包含书籍作者的作者排序值列表。 排序是作者元数据信息中的排序(与书籍中的author_sort不同)。 返回的列表的形式为``author sort 1`` val_separator author sort 2 等,不添加空格。 此列表中的作者排序值与书籍作者的顺序相同。 如果您想要“val_separator”周围有空格,则将它们包含在“val_separator”字符串中。

  • book_count(query, use_vl) – 返回通过搜索 query 找到的书籍数量。 如果“use_vl”为“0”(零),则虚拟库将被忽略。 此函数及其同伴“book_values()”在模板搜索中特别有用,支持组合多本书信息的搜索,例如查找仅包含一本书的系列。 除非将“allow_template_database_functions_in_composites”调整设置为 True,否则它不能在复合列中使用。 它只能在 GUI 中使用。

    For example this template search uses this function and its companion to find all series with only one book:

    1. Define a stored template (using Preferences → Advanced → Template functions) named series_only_one_book (the name is arbitrary). The template is:

      program:
          vals = globals(vals='');
          if !vals then
              all_series = book_values('series', 'series:true', ',', 0);
              for series in all_series:
                  if book_count('series:="' & series & '"', 0) == 1 then
                      vals = list_join(',', vals, ',', series, ',')
                  fi
              rof;
              set_globals(vals)
          fi;
          str_in_list(vals, ',', $series, 1, '')
      

    模板第一次运行时(检查的第一本书)它将数据库查找的结果存储在名为“vals”的“global”模板变量中。 这些结果用于检查后续书籍,而无需重新查找。

    1. Use the stored template in a template search:

      template:"program: series_only_one_book()#@#:n:1"
      

    Using a stored template instead of putting the template into the search eliminates problems caused by the requirement to escape quotes in search expressions.

  • book_values(column, query, sep, use_vl) – 返回列 column (查找名称)中包含的唯一值的列表,以 sep 分隔,在找到的书中 通过搜索“查询”。 如果“use_vl”为“0”(零),则虚拟库将被忽略。 该函数及其同伴“book_count()”在模板搜索中特别有用,支持组合多本书信息的搜索,例如查找仅包含一本书的系列。 除非将“allow_template_database_functions_in_composites”调整设置为 True,否则它不能在复合列中使用。 它只能在 GUI 中使用。

  • booksize() – returns the value of the calibre ‘size’ field. Returns ‘’ if there are no formats.

  • check_yes_no(field_name, is_undefined, is_false, is_true) – 检查由查找名称 field_name 命名的是/否字段的值是否是参数指定的值之一,返回 ' yes' 如果找到匹配项,否则返回空字符串。 将参数“is_undefined”、“is_false”或“is_true”设置为 1(数字)以检查该条件,否则将其设置为 0。示例:

    check_yes_no("#bool", 1, 0, 1) returns 'Yes' if the yes/no field #bool is either True or undefined (neither True nor False).

    More than one of is_undefined, is_false, or is_true can be set to 1.

  • ceiling(x) – returns the smallest integer greater than or equal to x. Throws an exception if x is not a number.

  • character(character_name) – returns the character named by character_name. For example, character('newline') returns a newline character ('\n'). The supported character names are newline, return, tab, and backslash.

  • cmp(x, y, lt, eq, gt) – compares x and y after converting both to numbers. Returns lt if x <# y, eq if x ==# y, otherwise gt. This function can usually be replaced with one of the numeric compare operators (==#, <#, >#, etc).

  • connected_device_name(storage_location_key) – if a device is connected then return the device name, otherwise return the empty string. Each storage location on a device has its own device name. The storage_location_key names are 'main', 'carda' and 'cardb'. This function works only in the GUI.

  • connected_device_uuid(storage_location_key) – 如果设备已连接,则返回设备 uuid(唯一 ID),否则返回空字符串。 设备上的每个存储位置都有不同的 uuid。 storage_location_key 位置名称为``’main’’carda’`` 和``’cardb’``。 此功能仅在 GUI 中有效。

  • current_library_name() – return the last name on the path to the current calibre library.

  • current_library_path() – return the full path to the current calibre library.

  • current_virtual_library_name() – return the name of the current virtual library if there is one, otherwise the empty string. Library name case is preserved. Example: program: current_virtual_library_name(). This function works only in the GUI.

  • date_arithmetic(date, calc_spec, fmt) – 使用 calc_specdate 计算新日期。 返回根据可选“fmt”格式化的新日期:如果未提供,则结果将采用 ISO 格式。 calc_spec 是由一对“vW”(“valueWhat”)连接而成的字符串,其中“v”是可能为负数,W 是以下字母之一:

    • s: add v seconds to date

    • m: add v minutes to date

    • h: add v hours to date

    • d: add v days to date

    • w: add v weeks to date

    • y: add v years to date, where a year is 365 days.

    Example: '1s3d-1m' will add 1 second, add 3 days, and subtract 1 minute from date.

  • days_between(date1, date2) – return the number of days between date1 and date2. The number is positive if date1 is greater than date2, otherwise negative. If either date1 or date2 are not dates, the function returns the empty string.

  • divide(x, y) – returns x / y. Throws an exception if either x or y are not numbers. This function can usually be replaced by the / operator.

  • eval(string) – 将字符串作为程序求值,传递局部变量。 这允许使用模板处理器从局部变量构造复杂的结果。 在“模板程序模式 <template_mode>”中,由于在评估模板之前解释“{”和“}”字符,因此必须对“{”字符使用“[[”,对“}”使用“]]” 特点。 它们会自动转换。 另请注意,使用“模板程序模式 <template_mode>”时,不能在此函数的参数中使用前缀和后缀(“|prefix|suffix”语法)。

  • extra_file_size(file_name) – 返回书籍的``data/`` 文件夹中额外文件``file_name`` 的大小,如果存在,否则返回``-1``。 另请参见函数“has_extra_files()”、“extra_file_names()”和“extra_file_modtime()”。 该功能只能在 GUI 中使用。

  • extra_file_modtime(file_name, format_string) – 返回书籍的``data/`` 文件夹中额外文件``file_name`` 的修改时间,如果存在,否则返回``-1``。 modtime 根据“format_string”进行格式化(有关详细信息,请参阅“format_date()”)。 如果“format_string”是空字符串,则返回 modtime 作为自纪元以来的浮点数秒数。 另请参见函数“has_extra_files()”、“extra_file_names()”和“extra_file_size()”。 纪元取决于操作系统。 该功能只能在 GUI 中使用。

  • extra_file_names(sep [,pattern]) 返回本书的 data/ 文件夹中以 sep 分隔的额外文件列表。 如果提供了可选参数“pattern”,一个正则表达式,则列表将被过滤到与“pattern”匹配的文件。 模式匹配不区分大小写。 另请参见函数“has_extra_files()”、“extra_file_modtime()”和“extra_file_size()”。 该功能只能在 GUI 中使用。

  • field(lookup_name) – returns the value of the metadata field with lookup name lookup_name.

  • field_exists(field_name) – checks if a field (column) with the lookup name field_name exists, returning '1' if so and the empty string if not.

  • finish_formatting(val, fmt, prefix, suffix) – 将格式、前缀和后缀应用于值,其方式与在诸如 {series_index:05.2f|' 等模板中执行的方式相同 - |- }。 提供此功能是为了轻松地将复杂的单功能或模板程序模式模板转换为“GPM”模板。 例如,以下程序产生与上述模板相同的输出:

    program: finish_formatting(field("series_index"), "05.2f", " - ", " - ")
    

    Another example: for the template {series:re(([^\s])[^\s]+(\s|$),\1)}{series_index:0>2s| - | - }{title} use:

    program:
      strcat(
        re(field('series'), '([^\s])[^\s]+(\s|$)', '\1'),
           finish_formatting(field('series_index'), '0>2s', ' - ', ' - '),
           field('title')
      )
    
  • first_matching_cmp(val, [ cmp, result, ]* else_result) – compares val < cmp in sequence, returning the associated result for the first comparison that succeeds. Returns else_result if no comparison succeeds. Example:

    i = 10;
    first_matching_cmp(i,5,"small",10,"middle",15,"large","giant")
    

    returns "large". The same example with a first value of 16 returns "giant".

  • first_non_empty(value [, value]*) – returns the first value that is not empty. If all values are empty, then the empty string is returned. You can have as many values as you want.

  • floor(x) – returns the largest integer less than or equal to x. Throws an exception if x is not a number.

  • format_date(val, format_string) – format the value, which must be a date string, using the format_string, returning a string. The formatting codes are:

    • d    : the day as number without a leading zero (1 to 31)

    • dd   : the day as number with a leading zero (01 to 31)

    • ddd  : the abbreviated localized day name (e.g. “Mon” to “Sun”).

    • dddd : the long localized day name (e.g. “Monday” to “Sunday”).

    • M    : the month as number without a leading zero (1 to 12).

    • MM   : the month as number with a leading zero (01 to 12)

    • MMM  : the abbreviated localized month name (e.g. “Jan” to “Dec”).

    • MMMM : the long localized month name (e.g. “January” to “December”).

    • yy   : the year as two digit number (00 to 99).

    • yyyy : the year as four digit number.

    • h    : the hours without a leading 0 (0 to 11 or 0 to 23, depending on am/pm)

    • hh   : the hours with a leading 0 (00 to 11 or 00 to 23, depending on am/pm)

    • m    : the minutes without a leading 0 (0 to 59)

    • mm   : the minutes with a leading 0 (00 to 59)

    • s    : the seconds without a leading 0 (0 to 59)

    • ss   : the seconds with a leading 0 (00 to 59)

    • ap   : use a 12-hour clock instead of a 24-hour clock, with ‘ap’ replaced by the localized string for am or pm.

    • AP   : use a 12-hour clock instead of a 24-hour clock, with ‘AP’ replaced by the localized string for AM or PM.

    • iso  : the date with time and timezone. Must be the only format present.

    • to_number   : convert the date & time into a floating point number (a timestamp)

    • from_number : convert a floating point number (a timestamp) into an iso formatted date. If you want a different date format then add the desired formatting string after from_number and a colon (:). Example: from_number:MMM dd yyyy

    You might get unexpected results if the date you are formatting contains localized month names, which can happen if you changed the date format tweaks to contain MMMM. In this case, instead of using the field() function as in:

    format_date(field('pubdate'), 'yyyy')
    

    use the raw_field() function as in:

    format_date(raw_field('pubdate'), 'yyyy')
    
  • format_date_field(field_name, format_string) – 格式化字段``field_name`` 中的值,该字段必须是日期字段的查找名称,标准或自定义。 有关格式化代码,请参阅“format_date()”。 此函数比 format_date 快得多,应在格式化字段(列)中的值时使用。 它不能用于计算日期或字符串变量中的日期。 例子:

    format_date_field('pubdate', 'yyyy.MM.dd')
    format_date_field('#date_read', 'MMM dd, yyyy')
    
  • formats_modtimes(date_format_string) – 返回以冒号分隔的项目的逗号分隔列表 FMT:DATE 表示书籍格式的修改时间。 “date_format_string”参数指定日期的格式。 有关详细信息,请参阅“format_date()”函数。 您可以使用“select”函数来获取特定格式的修改时间。 请注意,格式名称始终为大写,如 EPUB 中那样。

  • formats_paths() – 返回以冒号分隔的项目的逗号分隔列表 FMT:PATH 给出书籍格式的完整路径。 您可以使用 select 函数来获取特定格式的路径。 请注意,格式名称始终为大写,如 EPUB 中那样。

  • formats_sizes() – return a comma-separated list of colon-separated FMT:SIZE items giving the sizes in bytes of the formats of a book. You can use the select function to get the size for a specific format. Note that format names are always uppercase, as in EPUB.

  • fractional_part(x) – returns the value after the decimal point. For example, fractional_part(3.14) returns 0.14. Throws an exception if x is not a number.

  • get_link(field_name, field_value) – fetch the link for field field_name with value field_value. If there is no attached link, return the empty string. Examples:

  • The following returns the link attached to the tag Fiction:

    get_link('tags', 'Fiction')
    
  • This template makes a list of the links for all the tags associated with a book in the form value:link, ...:

    program:
     ans = '';
     for t in $tags:
         l = get_link('tags', t);
         if l then
             ans = list_join(', ', ans, ',', t & ':' & get_link('tags', t), ',')
         fi
     rof;
     ans
    
  • has_cover() – return 'Yes' if the book has a cover, otherwise the empty string.

  • has_extra_files([pattern]) – 返回额外文件的计数,否则返回 ‘’ (空字符串)。 如果提供了可选参数“pattern”(正则表达式),则在对文件进行计数之前,列表将被过滤为与“pattern”匹配的文件。 模式匹配不区分大小写。 另请参见函数“extra_file_names()”、“extra_file_size()”和“extra_file_modtime()”。 该功能只能在 GUI 中使用。

  • identifier_in_list(val, id_name [,found_val, not_found_val]) – 将 val 视为以逗号分隔的标识符列表。 标识符的格式为“id_name:value”。 id_name 参数是要搜索的 id_name 文本,可以是 id_nameid_name:regexp。 如果有任何标识符与 id_name 匹配,则第一种情况匹配。 如果 id_name 与标识符匹配并且正则表达式与标识符的值匹配,则第二种情况匹配。 如果提供了“found_val”和“not_found_val”,则如果存在匹配则返回“found_val”,否则返回“not_found_val”。 如果未提供 found_valnot_found_val ,则如果存在匹配则返回 identifier:value 对,否则返回空字符串 ('')。

  • is_marked() – check whether the book is marked in calibre. If it is then return the value of the mark, either 'true' (lower case) or a comma-separated list of named marks. Returns '' (the empty string) if the book is not marked. This function works only in the GUI.

  • language_codes(lang_strings) – 返回 lang_strings 中传递的语言名称的`语言代码 <https://www.loc.gov/standards/iso639-2/php/code_list.php>`_。 字符串必须采用当前区域设置的语言。 Lang_strings 是一个以逗号分隔的列表。

  • list_contains(value,separator, [pattern,found_val,]* not_found_val) –(in_list 的别名)将值解释为由``separator`` 分隔的项目列表,评估 `` 针对列表中的每个值的pattern``。 如果“pattern”匹配任何值,则返回“found_val”,否则返回“not_found_val”。 “pattern” 和 “found_value” 可以根据需要重复多次,允许根据搜索返回不同的值。 按顺序检查模式。 返回第一个匹配项。 别名:in_list()list_contains()

  • list_count(value, separator) – interprets value as a list of items separated by separator, returning the count of items in the list. Aliases: count(), list_count()

  • list_count_matching(list, pattern, separator) – interprets list as a list of items separated by separator, returning the number of items in the list that match the regular expression pattern. Aliases: list_count_matching(), count_matching()

  • list_difference(list1, list2, separator) – return a list made by removing from list1 any item found in list2 using a case-insensitive comparison. The items in list1 and list2 are separated by separator, as are the items in the returned list.

  • list_equals(list1, sep1, list2, sep2, yes_val, no_val) – 如果``list1`` 和``list2` 包含相同的项目,则返回``yes_val``,否则返回``no_val``。 通过使用适当的分隔符(“sep1”或“sep2”)分割每个列表来确定项目。 列表中项目的顺序不相关。 比较不区分大小写。

  • list_intersection(list1, list2, separator) – return a list made by removing from list1 any item not found in list2, using a case-insensitive comparison. The items in list1 and list2 are separated by separator, as are the items in the returned list.

  • list_join(with_separator,list1,separator1 [,list2,separator2]*) – 返回通过在项目之间使用``with_separator``连接源列表(``list1``等)中的项目而创建的列表 在结果列表中。 每个源“list[123…]”中的项目由关联的“separator[123…]”分隔。 列表可以包含零值。 它可以是像“publisher”这样的单值字段,实际上是一个单项列表。 使用不区分大小写的比较删除重复项。 项目按照它们在源列表中出现的顺序返回。 如果列表中的项目仅字母大小写不同,则使用最后一个。 所有分隔符都可以是多个字符。

    例如:

    program:
      list_join('#@#', $authors, '&', $tags, ',')
    

    You can use list_join on the results of previous calls to list_join as follows:

    program:
      a = list_join('#@#', $authors, '&', $tags, ',');
      b = list_join('#@#', a, '#@#', $#genre, ',', $#people, '&', 'some value', ',')
    

    You can use expressions to generate a list. For example, assume you want items for authors and #genre, but with the genre changed to the word “Genre: “ followed by the first letter of the genre, i.e. the genre “Fiction” becomes “Genre: F”. The following will do that:

    program:
      list_join('#@#', $authors, '&', list_re($#genre, ',', '^(.).*$', 'Genre: \1'),  ',')
    
  • list_re(src_list,separator, include_re, opt_replace) – 首先使用``separator`` 字符将``src_list`` 分隔成项目来构造一个列表。 对于列表中的每个项目,检查它是否与“include_re”匹配。 如果是,则将其添加到要返回的列表中。 如果“opt_replace”不是空字符串,则在将项目添加到返回的列表之前应用替换。

  • list_re_group(src_list,separator, include_re, search_re [, template_for_group]*) – 与 list_re 类似,但替换不是可选的。 它在进行替换时使用“re_group(item, search_re, template …)”。

  • list_remove_duplicates(list, separator) – return a list made by removing duplicate items in list. If items differ only in case then the last is returned. The items in list are separated by separator, as are the items in the returned list.

  • list_sort(list, direction, separator) – return list sorted using a case-insensitive lexical sort. If direction is zero, list is sorted ascending, otherwise descending. The list items are separated by separator, as are the items in the returned list.

  • list_split(list_val, sep, id_prefix) – splits list_val into separate values using sep, then assigns the values to local variables named id_prefix_N where N is the position of the value in the list. The first item has position 0 (zero). The function returns the last element in the list.

    例如:

    list_split('one:two:foo', ':', 'var')
    

    is equivalent to:

    var_0 = 'one';
    var_1 = 'two';
    var_2 = 'foo
    
  • list_union(list1, list2, separator) – return a list made by merging the items in list1 and list2, removing duplicate items using a case-insensitive comparison. If items differ in case, the one in list1 is used. The items in list1 and list2 are separated by separator, as are the items in the returned list. Aliases: merge_lists(), list_union()

  • mod(x, y) – returns the floor of the remainder of x / y. Throws an exception if either x or y is not a number.

  • multiply(x [, y]*) – returns the product of its arguments. Throws an exception if any argument is not a number. This function can usually be replaced by the * operator.

  • not(value) – returns the string “1” if the value is empty, otherwise returns the empty string. This function can usually be replaced with the unary not (!) operator.

  • ondevice() – return the string 'Yes' if ondevice is set, otherwise return the empty string.

  • or(value [, value]*) – 如果任何值不为空,则返回字符串 '1',否则返回空字符串。 您可以拥有任意多个值。 该函数通常可以用“||”运算符替换。 无法更换的一个原因是短路会因副作用而改变结果。

  • print(a [, b]*) – prints the arguments to standard output. Unless you start calibre from the command line (calibre-debug -g), the output will go into a black hole. The print function always returns its first argument.

  • range(start, stop, step, limit) – 返回通过在参数 start、stop 和 step 指定的范围内循环生成的数字列表,最大长度为 limit。 产生的第一个值是“start”。 后续值``next_v = current_v + step``。 假设“step”为正,则“next_v < stop”时循环继续,否则当“next_v > stop”时继续。 如果“start”未通过测试,则会生成一个空列表:如果“step”为正,则“start >= stop”。 “limit” 设置列表的最大长度,默认值为 1000。参数“start”、“step” 和“limit” 是可选的。 使用一个参数调用“range()”指定“stop”。 两个参数指定“start”和“stop”。 三个参数指定“start”、“stop”和“step”。 四个参数指定“start”、“stop”、“step”和“limit”。 例子:

    range(5) -> '0, 1, 2, 3, 4'
    range(0, 5) -> '0, 1, 2, 3, 4'
    range(-1, 5) -> '-1, 0, 1, 2, 3, 4'
    range(1, 5) -> '1, 2, 3, 4'
    range(1, 5, 2) -> '1, 3'
    range(1, 5, 2, 5) -> '1, 3'
    range(1, 5, 2, 1) -> error(limit exceeded)
    
  • raw_field(lookup_name [, optional_default]) – returns the metadata field named by lookup_name without applying any formatting. It evaluates and returns the optional second argument optional_default if the field’s value is undefined (None).

  • raw_list(lookup_name, separator) – returns the metadata list named by lookup_name without applying any formatting or sorting, with the items separated by separator.

  • re_group(value, pattern [, template_for_group]*) – return a string made by applying the regular expression pattern to value and replacing each matched instance with the value returned by the corresponding template. In Template Program Mode, like for the template and the eval functions, you use [[ for { and ]] for }.

    The following example looks for a series with more than one word and uppercases the first word:

    program: re_group(field('series'), "(\S* )(.*)", "{$:uppercase()}", "{$}")'}
    
  • round(x) – returns the nearest integer to x. Throws an exception if x is not a number.

  • series_sort() – returns the series sort value.

  • strcat(a [, b]*) – can take any number of arguments. Returns a string formed by concatenating all the arguments.

  • strcat_max(max, string1 [, prefix2, string2]*) – 返回通过连接参数形成的字符串。 返回值被初始化为“string1”。 只要生成的字符串长度小于“max”,由“prefix, string”对组成的字符串就会添加到值的末尾。 前缀可以为空。 即使“string1”比“max”长,也会返回“string1”。 您可以根据需要传递任意数量的“前缀、字符串”对。

  • strcmp(x, y, lt, eq, gt) – does a case-insensitive lexical comparison of x and y. Returns lt if x < y, eq if x == y, otherwise gt. This function can often be replaced by one of the lexical comparison operators (==, >, <, etc.)

  • strcmpcase(x, y, lt, eq, gt) – does a case-sensitive lexical comparison of x and y. Returns lt if x < y, eq if x == y, otherwise gt.

    Note: This is NOT the default behavior used by calibre, for example, in the lexical comparison operators (==, >, <, etc.). This function could cause unexpected results, preferably use strcmp() whenever possible.

  • strlen(value) – Returns the length of the string value.

  • substr(str, start, end) – 返回``str`` 的第``start``’ 个字符到第``end``’ 个字符。 “str” 中的第一个字符是第零个字符。 如果“end”为负数,则表示从右边数起有很多字符。 如果“end”为零,则表示最后一个字符。 例如, substr('12345', 1, 0) 返回 '2345',而 substr('12345', 1, -1) 返回 '234'

  • subtract(x, y) – returns x - y. Throws an exception if either x or y are not numbers. This function can usually be replaced by the - operator.

  • switch_if([test_expression, value_expression,]+ else_expression) – 对于每个 test_expression, value_expression 对,检查 test_expression 是否为 True(非空),如果是则返回 ` 值_表达式`。 如果没有“test_expression”为 True,则返回“else_expression”的结果。 您可以根据需要拥有任意多个“test_expression, value_expression”对。

  • today() – return a date+time string for today (now). This value is designed for use in format_date or days_between, but can be manipulated like any other string. The date is in ISO date/time format.

  • template(x) – evaluates x as a template. The evaluation is done in its own context, meaning that variables are not shared between the caller and the template evaluation.

  • to_hex(val) – returns the string val encoded in hex. This is useful when constructing calibre URLs.

  • urls_from_identifiers(identifiers, sort_results) – 给定一个以逗号分隔的“identifiers”列表,其中“identifier”是一对以冒号分隔的值(“id_name:id_value”),返回一个 从标识符生成的以逗号分隔的 HTML URL 列表。 如果 sort_results 为“0”(字符或数字),则列表不排序,否则按标识符名称的字母顺序排序。 URL 的生成方式与“图书详细信息”中显示的内置标识符列相同。

More complex programs in template expressions - Template Program Mode

“模板程序模式”(“TPM”) 是“通用程序模式 <general_mode>”和“单功能模式 <single_mode>”的混合。 “TPM”与单函数模式的不同之处在于它允许编写引用其他元数据字段的模板表达式、使用嵌套函数、修改变量和进行算术。 它与“通用程序模式”的不同之处在于,模板包含在“{”和“}”字符之间,并且不以单词“program:”开头。 模板的程序部分是通用程序模式表达式列表。

示例:假设您希望模板显示一本书的系列,如果有,否则显示自定义字段 #genre 的值。 您无法在“单函数模式 <single_mode>”中执行此操作,因为您无法引用模板表达式中的另一个元数据字段。 在“TPM”中,您可以,如以下表达式所示:

{#series:'ifempty($, field('#genre'))'}

The example shows several things:

  • TPM is used if the expression begins with :' and ends with '}. Anything else is assumed to be in Single Function Mode.

  • the variable $ stands for the field named in the template: the expression is operating upon, #series in this case.

  • functions must be given all their arguments. There is no default value. For example, the standard built-in functions must be given an additional initial parameter indicating the source field.

  • white space is ignored and can be used anywhere within the expression.

  • constant strings are enclosed in matching quotes, either ' or ".

All the functions listed under Single Function Mode and General Program Mode can be used in TPM.

在“TPM”中,在字符串文字中使用“{”和“}”字符可能会导致错误或意外结果,因为它们会混淆模板处理器。 它尝试将它们视为模板表达式边界,而不是字符。 在某些情况下,但不是所有情况下,您可以将 { 替换为 [[ ,将 } 替换为 ]] 。 一般来说,如果您的程序包含“{”和“}”字符,那么您应该使用“通用程序模式”。

与“通用程序模式”一样,对于“单函数模式 <single_mode>”下记录的函数,除了记录的参数之外,您还必须提供函数要执行的值作为第一个参数。 在“TPM”中,您可以使用“$”来访问模板表达式的“查找名称”指定的值。

Python Template Mode

Python 模板模式 (PTM) 允许您使用本机 python 和 calibre API <https://manual.calibre-ebook.com/develop.html#api-documentation-for-various-parts-of-calibre> 编写模板 _。 数据库 API 将是最常用的; 进一步的讨论超出了本手册的范围。 PTM 模板速度更快,可以执行更复杂的操作,但您必须知道如何使用 calibre API 在 python 中编写代码。

A PTM template begins with:

python:
def evaluate(book, context):
    # book is a calibre metadata object
    # context is an instance of calibre.utils.formatter.PythonTemplateContext,
    # which currently contains the following attributes:
    # db: a calibre legacy database object.
    # globals: the template global variable dictionary.
    # arguments: is a list of arguments if the template is called by a GPM template, otherwise None.
    # funcs: used to call Built-in/User functions and Stored GPM/Python templates.
    # Example: context.funcs.list_re_group()

    # your Python code goes here
    return 'a string'

You can add the above text to your template using the context menu, usually accessed with a right click. The comments are not significant and can be removed. You must use python indenting.

The context object supports str(context) that returns a string of the context’s contents, and context.attributes that returns a list of the attribute names in the context.

context.funcs 属性允许调用内置和用户模板函数以及存储的 GPM/Python 模板,以便您可以直接在代码中执行它们。 使用函数的名称来检索函数。 如果名称与 Python 关键字冲突,请在名称末尾添加下划线。 例子:

context.funcs.list_re_group()
context.funcs.assert_()

以下是 PTM 模板的示例,该模板生成一个系列的所有作者的列表。 该列表存储在“从其他列构建的列,行为类似于标签”中。 它显示在“书籍详细信息”中,并选中“在单独的行上”(在“首选项->外观->书籍详细信息”中)。 该选项要求列表以逗号分隔。 为了满足该要求,模板将作者姓名中的逗号转换为分号,然后构建以逗号分隔的作者列表。 然后对作者进行排序,这就是模板使用author_sort的原因。

python:
def evaluate(book, context):
    if book.series is None:
        return ''
    db = context.db.new_api
    ans = set()
    # Get the list of books in the series
    ids = db.search(f'series:"={book.series}"', '')
    if ids:
        # Get all the author_sort values for the books in the series
        author_sorts = (v for v in db.all_field_for('author_sort', ids).values())
        # Add the names to the result set, removing duplicates
        for aus in author_sorts:
            ans.update(v.strip() for v in aus.split('&'))
    # Make a sorted comma-separated string from the result set
    return ', '.join(v.replace(',', ';') for v in sorted(ans))

The output in Book details looks like this:

E-book conversion dialog

保存的模板

“通用程序模式 <general_mode>”和“Python 模板模式 <python_mode>”都支持保存模板并从另一个模板调用这些模板,就像调用存储的函数一样。 您可以使用“首选项->高级->模板功能”保存模板。 该对话框中提供了更多信息。 您可以像调用函数一样调用模板,并根据需要传递位置参数。 参数可以是任何表达式。 调用模板的示例,假设存储的模板名为“foo”:

  • foo() – call the template passing no arguments.

  • foo(a, b) call the template passing the values of the two variables a and b.

  • foo(if field('series') then field('series_index') else 0 fi) – if the book has a series then pass the series_index, otherwise pass the value 0.

在 GPM 中,您可以使用“arguments”函数检索在调用存储模板时传递的参数。 它声明并初始化局部变量,即有效的参数。 变量是位置变量; 他们在同一位置获取调用中给出的参数值。 如果调用中未提供相应的参数,则“arguments”会为该变量分配提供的默认值。 如果没有默认值,则该变量将设置为空字符串。 例如,以下“arguments”函数声明 2 个变量“key”、“alternate”:

arguments(key, alternate='series')

Examples, again assuming the stored template is named foo:

  • foo('#myseries') – argument key is assigned the value 'myseries' and the argument alternate is assigned the default value 'series'.

  • foo('series', '#genre') the variable key is assigned the value 'series' and the variable alternate is assigned the value '#genre'.

  • foo() – the variable key is assigned the empty string and the variable alternate is assigned the value 'series'.

In PTM the arguments are passed in the arguments parameter, which is a list of strings. There isn’t any way to specify default values. You must check the length of the arguments list to be sure that the number of arguments is what you expect.

测试存储模板的一种简单方法是使用“模板测试器”对话框。 为了便于访问,请在“首选项->高级->键盘快捷键->模板测试器”中为其提供键盘快捷键。 为“存储的模板”对话框提供快捷方式将有助于在测试器和编辑存储的模板的源代码之间更快地切换。

Providing additional information to templates

A developer can choose to pass additional information to the template processor, such as application-specific book metadata or information about what the processor is being asked to do. A template can access this information and use it during the evaluation.

Developer: how to pass additional information

附加信息是一个包含“变量名:变量值”对的 Python 字典,其中值必须是字符串。 模板可以访问字典,创建名为“variable_name”的模板局部变量,其中包含值“variable_value”。 用户无法更改名称,因此最好使用不会与其他模板局部变量冲突的名称,例如在名称前添加下划线。

This dictionary is passed to the template processor (the formatter) using the named parameter global_vars=your_dict. The full method signature is:

def safe_format(self, fmt, kwargs, error_value, book,
                column_name=None, template_cache=None,
                strip_results=True, template_functions=None,
                global_vars={})

Template writer: how to access the additional information

You access the additional information (the globals dictionary) in a template using the template function:

globals(id[=expression] [, id[=expression]]*)

其中“id”是任何合法的变量名称。 该函数检查开发者提供的附加信息中是否包含该名称。 如果是,则该函数将提供的值分配给具有该名称的模板局部变量。 如果附加信息中没有该名称,并且提供了“表达式”,则计算“表达式”并将结果分配给局部变量。 如果既没有提供值也没有提供表达式,函数会将空字符串 ('') 分配给局部变量。

A template can set a value in the globals dictionary using the template function:

set_globals(id[=expression] [, id[=expression]]*)

This function sets the globals dictionary key:value pair id:value where value is the value of the template local variable id. If that local variable doesn’t exist then value is set to the result of evaluating expression.

Notes on the difference between modes

The three program modes, Single Function Mode (SFM), Template Program Mode (TPM), and General Program Mode (GPM), work differently. SFM is intended to be ‘simple’ so it hides a lot of programming language bits.

Differences:

  • In SFM the value of the column is always passed as an ‘invisible’ first argument to a function included in the template.

  • SFM doesn’t support the difference between variables and strings; all values are strings.

  • The following SFM template returns either the series name or the string “no series”:

    {series:ifempty(no series)}
    

    The equivalent template in TPM is

    {series:'ifempty($, 'no series')'}
    

    The equivalent template in GPM is:

    program: ifempty(field('series'), 'no series')
    

    The first argument to ifempty is the value of the field series. The second argument is the string no series. In SFM the first argument, the value of the field, is automatically passed (the invisible argument).

  • Several template functions, for example booksize() and current_library_name(), take no arguments. Because of the ‘invisible argument’ you cannot use these functions in SFM.

  • Nested functions, where a function calls another function to compute an argument, cannot be used in SFM. For example this template, intended to return the first 5 characters of the series value uppercased, won’t work in SFM:

    {series:uppercase(substr(0,5))}
    
  • TPM and GPM support nested functions. The above template in TPM would be:

    {series:'uppercase(substr($, 0,5))'}
    

    In GPM it would be:

    program: uppercase(substr(field('series'), 0,5))
    
  • 如上面“模板程序模式 1”部分所述,在“TPM”字符串文字中使用“{”和“}”字符可能会导致错误或意外结果,因为它们会混淆模板处理器。 它尝试将它们视为模板边界,而不是字符。 在某些情况下,但不是所有情况下,您可以将 { 替换为 [[ ,将 } 替换为 ]] 。 一般来说,如果您的程序包含“{”和“}”字符,那么您应该使用“通用程序模式”。

User-defined Python template functions

您可以将自己的 Python 函数添加到模板处理器。 这些函数可以在三种模板编程模式中的任何一种中使用。 通过转到“首选项 -> 高级 -> 模板函数”来添加这些函数。 该对话框中显示了说明。

Special notes for save/send templates

当模板用于“保存到磁盘”或“发送到设备”模板时,会应用特殊处理。 字段的值被清理,用下划线替换文件系统特有的字符,包括斜杠。 这意味着字段文本不能用于创建文件夹。 但是,前缀或后缀字符串中的斜杠不会更改,因此这些字符串中的斜杠将导致创建文件夹。 因此,您可以创建可变深度的文件夹结构。

For example, assume we want the folder structure series/series_index - title, with the caveat that if series does not exist, then the title should be in the top folder. The template to do this is:

{series:||/}{series_index:|| - }{title}

The slash and the hyphen appear only if series is not empty.

查找功能让我们可以进行更高级的处理。 例如,假设一本书有一个系列,那么我们需要文件夹结构“系列/系列索引 - title.fmt”。 如果这本书没有系列,那么我们需要文件夹结构“genre/author_sort/title.fmt”。 如果这本书没有类型,那么我们想使用“未知”。 我们想要两条完全不同的路径,具体取决于系列的值。

To accomplish this, we:

  1. Create a composite field (give it lookup name #aa) containing {series}/{series_index} - {title}. If the series is not empty, then this template will produce series/series_index - title.

  2. Create a composite field (give it lookup name #bb) containing {#genre:ifempty(Unknown)}/{author_sort}/{title}. This template produces genre/author_sort/title, where an empty genre is replaced with Unknown.

  3. Set the save template to {series:lookup(.,#aa,#bb)}. This template chooses composite field #aa if series is not empty and composite field #bb if series is empty. We therefore have two completely different save paths, depending on whether or not series is empty.

Tips

  • Use the Template Tester to test templates. Add the tester to the context menu for books in the library and/or give it a keyboard shortcut.

  • Templates can use other templates by referencing composite columns built with the desired template. Alternatively, you can use Stored Templates.

  • In a plugboard, you can set a field to empty (or whatever is equivalent to empty) by using the special template {}. This template will always evaluate to an empty string.

  • The technique described above to show numbers even if they have a zero value works with the standard field series_index.

Function reference