【问题标题】:How can I use a script to change some text in an epub file?如何使用脚本更改 epub 文件中的某些文本?
【发布时间】:2012-02-17 16:49:05
【问题描述】:

我最近买了一个 Nook Simple Touch。我使用 Calibre 管理我的电子书,并将它们传输到 Nook。

由于 B&N 对 epub 规范的非标准实施,Nook ST 在从许多来源获得封面图像时不会显示它们。此处描述了该问题:http://john.nachtimwald.com/2011/08/21/nook-covers-not-showing-up/ 基本上,Nook ST 要求封面的 XML 属性采用以下格式:

<meta name="cover" content="id5" />

但许多 epub 创作者都以这种方式使用它们:

<meta content="id5" name="cover" />

然后 Nook ST 会完全忽略封面图片。

我一直在手动编辑我的 epub 文件中的 content.opf 文件。到目前为止,他们都有图像元,但它总是围绕“错误”的方式(根据 Nook 的说法是错误的)。

最近我一直在玩 REGEX,主要是为了尝试自动清理 Calibre 从 PDF 文件转换的 epub。我仍然是 REGEX 的初学者。

我想知道如何自动交换“名称”和“内容”属性?我认为它可以通过 REGEX 和脚本的组合来完成。我知道我拥有的其他一些与 epub 相关的脚本是用 Python 编写的。我在 Mac (OS X) 上,它们似乎运行良好。 AppleScript 也可能是一个不错的选择,尽管我希望人们可以在任何平台上运行它,因为我相信其他人会发现这很有用。

以下是我预见的步骤:

~解压epub文件

~使用正则表达式查找:

<meta content="???" name="cover">

~ 如果找到,使用 REGEX 将其更改为:

<meta name="cover" content="???">

~ 使用正确的压缩过程将提取的文件压缩回 epub。

我在这里找到了信息:http://www.mobileread.com/forums/showthread.php?t=55681 解释如何正确压缩 epub 文件。基本上它需要这两个命令:

zip -X0 "full path to new epub file" mimetype
zip -rDX9 "full path to new epub file" * -x "*.DS_Store" -x mimetype

我想将生成的脚本发布到任何可能找到和使用的地方(直到 B&N 解决他们糟糕的 epub/XML 实现)。我想到了在 Calibre 论坛和 mobileread 论坛上发布它(因为它们是我熟悉的两个,并且已经看到人们讨论此问题的手动修复)。

有人可以指导我如何创建这样的脚本吗?理想情况下,我很想真正知道如何创建脚本,这样随着时间的推移,我可以自己开始弄清楚这些事情(尤其是 REGEX 部分,因为我越来越看到它是多么有用)。

谢谢。

乔纳森

@Haldean:添加以说明我在对 Haldean 的评论中关于使他的脚本递归地通过所有子文件夹中的所有 content.opf 文件工作的意思。

> My_expanded_epubs
- -> epub_one_expanded
- - - -> content.opf
- -> epub_two_expanded
- - - -> content.opf
- -> epub_three_expanded
- - - -> content.opf
etc.

【问题讨论】:

  • 你有一个正则表达式可以正确识别你正在寻找的元标签吗?
  • 另外,你应该向 B&N 投诉。没有任何理由让 XML 处理器要求属性按任何特定顺序排列。
  • 谢谢马尔辛。我现在正在向 B&N 发送有关此问题的消息。
  • 我在 Stackoverflow 和 Google 上搜索了“解压 epub 文件 python”,但没有发现任何有用的信息。我有这个想法是在叫错树吗?我发现了很多关于使用 python 从 epub 中删除 DRM 的内容,但不是简单地解压 epub(并重新打包)。我知道我很可能会使用 AppleScript 将各个步骤拼凑在一起,但我真的希望它独立于平台。

标签: python regex automation epub


【解决方案1】:

如果您愿意使用 shell 脚本(我认为这是一个更好的选择),那么您可以使用 sed 单线:

sed 's/<meta content="\(.*\)" name="cover" \/>/<meta name="cover" content="\1" \/>/' [your-file]

这应该将content 属性首先出现的所有元行替换为具有正确顺序的元行。一个等效的 Python 翻译是:

import re
import sys
with open(sys.argv[1]) as f:
  for line in f:
    # Match this line to the wrong-way-around meta tag, put the content in group 1
    m = re.match(r'<meta content="(.*)" name="cover" />', line)
    if not m:
      print line
    else:
      print '<meta name="cover" content="%s" />' % m.group(1)

【讨论】:

  • 请注意,您的正则表达式对间距的任何变化都不可靠。
  • 感谢 Haldean。 Python 看起来是一种相对简单的语言,让我很容易理解。让我想起了大概 25 年前我玩过的 Basic..由于他提到的原因,我会尝试一下,也许使用 Marcin 提供的正则表达式。
  • @Haldean:你碰巧知道如何使用 Python 解包和重新打包 epub 文件吗?我似乎无法在任何地方找到该信息。它需要按照我原始帖子中指定的方式进行。
  • @Haldean 好吧,我一直在搞乱 Python,但还没有设法让我的头脑(或代码)了解如何实现 Marcin 建议的略有不同的正则表达式。我也很高兴知道如何让这个脚本递归地检查所有文件夹(扩展的 epub 文件)中的 content.opf 文件。我尝试在此处放置一个示例,但 cmets 无法识别换行符,因此我已将其添加到原始帖子的末尾。
【解决方案2】:

我建议您使用 sed 处理解压后的文件,并执行以下操作:

sed -e 's/<[ ]*meta[ ]*content[ ]*=[ ]*"\(.*\)"[ ]*name[ ]*=[ ]*"cover"[ ]*\/*[ ]*>/<meta name="cover" content="\1" \/>/g'

请注意,此版本将处理多余或缺少的空格或斜线。

您可能希望随后使用 xml 处理器(我建议使用使用 lxml 的 python 脚本)来验证您的编辑没有针对任何创建的无效标记。

使用任何类型的 XML 工具来执行操作在极端情况下都没有吸引力,因为完全兼容的 XML 处理器可能会进行其他完全合法的更改,并且还会触发您的角落中的其他错误。使用sed,您可以只编辑文档中您想要编辑的部分。

【讨论】:

  • 感谢您如此周到地考虑这一点。我会尽快尝试您的建议(整个下午都处于离线状态,因此响应延迟)。如果标签操作都很好,我想解决的另一个步骤是如何处理其他步骤。例如,解压 epub,运行正则表达式检查,重新打包 epub。如果有人有很多 epub 文件,他们希望将其侧载到他们的 Nook ST 中,那么大部分时间将花在解包和重新打包上。最好只在文件上运行脚本,递归处理其中的所有 epub 文件。
  • 我可以使用 Calibre 轻松地批量验证 epub 本身(据我回忆)。会是个好主意。谢谢。
  • @inspiredlife:如果您在拆包等方面遇到问题,那么我建议您发布一个单独的问题。
【解决方案3】:

就我个人而言,我不会使用正则表达式 (its the wrong tool) 来执行此操作。你能用 XSLT 吗?


编辑:

这是一个演示。 http://www.xsltcake.com/slices/nvLRJ6

有多个XSLT librarys for python


编辑:

如果你坚持使用正则表达式,你会想要这样的模式:
&lt;meta content="([^"]+)" name="([^"]+)" \/&gt;

我用disclaimer that this is the wrong tool 这么说,但有些极端情况会导致这不可靠,我不推荐它。

http://regexr.com?301uq

【讨论】:

  • 好的。谢谢你的建议。我已经查看了您提供的链接。我不清楚如何使用 XSLT(到目前为止我从未听说过)作为自动化手头任务的一部分。有什么建议?我还阅读了您链接的页面链接的页面。我没有找到任何我能够弄清楚如何继续前进的东西。
  • 所以我一直在学习更多关于为什么正则表达式可能不是定位相关 XML 属性的方法。虽然我还不相信不可能使用正则表达式来找到如此简单的东西。这可能是由于我对正则表达式的局限性一无所知。
  • @inspiredlife:我会说正则表达式是正确的工具,因为可能无法强制符合标准的 XML 解析器以所需的顺序输出属性,以及任何涉及解析整体的解决方案记录在受影响的实施中触发其他错误的风险。相比之下,sed 之类的工具将允许您仅编辑要更改的文档部分。
【解决方案4】:

我同意zapthedingbat's answer:这是一个 XML 问题,所以让我们使用专门为 XML 设计的工具,即 XSLT。

由于您是 XSLT 的新手,因此您需要一个 XSLT 处理器来尝试这个解决方案。如果你使用 *nix,xsltproc 是一个命令行处理器,几乎可以肯定默认安装,你可以从表面上接受这个解决方案。如果没有,您需要查看您选择的语言是否有用于执行 XSL 转换的 API。

这里有一个非常简单的重新排序属性的通用解决方案:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="@*|node()">
  <!-- copy everything as is -->
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="meta">
    <!-- except for the <meta/> element, reverse the attribute order -->
    <meta name="{@name}" content="{@content}"/>
  </xsl:template>
</xsl:stylesheet>

这是你的例子:

<root>
  <meta content="id5" name="cover" />
</root>

使用xsltproc 运行 XSLT:

$ xsltproc so.xsl so.xml

结果:

<root>
  <meta name="cover" content="id5"/>
</root>

【讨论】:

  • 为什么投反对票?这个答案完全满足了How can I use a script to change some text in an epub file?这个问题
  • 使用任何类型的 XML 处理都极不吸引人,因为您不知道哪些有效标记会触发其他错误。这里需要有针对性的文本编辑。
  • @Marcin 你能说“没有吸引力”吗?
  • 阅读我剩下的句子。
  • @Marcin 你能证明这行不通吗?因为它可能引起问题而将答案标记下来似乎不公平。我完全赞成学习新事物并在面对事实时采取不同的立场,但据我所知,这只是猜测。
猜你喜欢
  • 2019-08-05
  • 2014-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-03
相关资源
最近更新 更多