如何使用脚本更改epub文件中的某些文本?

时间:2012-02-17 16:49:05

标签: python regex automation epub

我最近买了一个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和脚本的组合来完成。我知道我在Python中使用的其他一些与epub相关的脚本。我在Mac(OS X)上,他们似乎运行良好。 AppleScript也可能是一个不错的选择,虽然我想要一些人可以在任何平台上运行的东西,因为我相信其他人会觉得这很有用。

以下是我预见的步骤:

〜解压缩epub文件

〜使用REGEX查找:

<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&amp; N解决他们糟糕的epub / XML实现)。在Calibre论坛和mobileread论坛上发布它(因为它们是我熟悉的两个,并且已经看到人们讨论这个问题的手册修复)。

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

谢谢。

乔纳森

@Haldean:ADDED用于说明我对Haldean的评论意味着他的脚本是否以递归方式处理所有子文件夹中的所有content.opf文件。

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

4 个答案:

答案 0 :(得分:2)

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

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)

答案 1 :(得分:1)

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

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

请注意,此版本将处理额外或缺少的空格或斜杠。

您可能希望随后使用xml处理器(我建议使用lxml创建一个python脚本)来验证您的编辑是否适用于任何创建的无效标记。

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

答案 2 :(得分:0)

我个人不会用正则表达式(its the wrong tool)来做这件事。你能用XSLT吗?


编辑:

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

有许多XSLT librarys for python


编辑:

如果你坚持用正则表达式做,你会想要一个这样的模式:
<meta content="([^"]+)" name="([^"]+)" \/>

我用disclaimer that this is the wrong tool说这个,并且有一些边缘情况会导致这种情况不可靠,我不推荐它。

http://regexr.com?301uq

答案 3 :(得分:-1)

我同意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>