更改2个或更多LibreOffice文档以具有完全相同的样式/格式


14

假设我有一个目录,其中包含约100个.rtf文件,这些文件是我使用LibreOffice Writer编辑的。

我希望该目录中的所有文件都具有完全相同的基本RTF样式指令,例如:

* font-family: Ubuntu             # All text in all files is now Ubuntu;
* font-size: 12px                 # All text in all files is now 12px big;
h1: 28px                          # All h1's are now 28px big;
if font-size: 18px {make it 22px} # All text with font-size 18px is now 22px;

依此类推...因此,基本上,我想一次更改所有文件。这样的“批量样式”可能吗?

也许以某种方式使用CLI是可能的?


3
我认为这将不是一件容易的事。如果它们的结构都相同,则可以使用一些骇人听闻的解决方案,从命令行替换.rtf文件中的文本。但是,这很大程度上取决于rtf文件的外观和相似程度。
塞巴斯蒂安·史塔克

从今晚开始,我在堆栈溢出中找到了一个全新的LibreOffice Writer宏的帮助。我们不再需要知道所有可能的现有字体大小。
WinEunuuchs2Unix '18

在最后的努力中,我已请Stack Overflow专家在宽限期结束之前在此处发布答案:stackoverflow.com/questions/49640951/…–
WinEunuuchs2Unix

你们有成千上万的声望点。我谦虚地建议您考虑给500-750。只是一个考虑。只是而已。
JohnDoea

Answers:


5

使用Libreoffice工具而不是CLI

当您拥有的都是命令行工具时,一切看起来都像是命令行问题。我决定使用LibreOffice宏编写此答案:

  1. 使用命令行循环在“无头”环境中处理每个Writer文档。
  2. 运行宏以更改.rtf(富文本格式)Writer文档文件。
  3. 宏保存文件并退出
  4. 循环回到1。

创建测试数据

创建两个或多个包含以下内容的文件:

richtext2.png

创建~/Downloads/copy-rtf.sh包含以下内容的脚本:

cp ~/Documents/*.rtf ~/Downloads

使用标记为可执行文件

chmod a+x ~/Downloads/copy-rtf.sh
  • 在开发和测试过程中,修改*.rtf文件的宏将针对~/Downloads目录运行。
  • 每种测试类型cd ~/Downloads和运行之前./copy-rtf.sh
  • 输出完美后,它们将被复制回活动目录。

之所以使用Downloads目录,是因为:

  • 每个人都有 ~/Downloads
  • 它会定期添加并手动清空
  • 它比/tmp/目录可能更永久,而目录可能不会在重新启动后持续存在。

在无头环境中运行宏

使用此Stack Exchange答案从命令行调用Libreoffice Writer并将其传递给全局宏名称以执行:

soffice -headless -invisible "vnd.sun.star.script:Standard.Module1.MySubroutine? language=Basic&location=application"

上面的答案可能不起作用,因此可以尝试另一种方法

soffice "macro:///Standard.SaveCSV.Main" $1

安装Java运行时环境

要运行宏,您需要安装Java Runtime Environment(JRE)。开发者的网页上有有关手动下载和安装的说明

然而,这个澳大利亚问答:https : //askubuntu.com/a/728153/307523建议它很简单:

sudo apt-add-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java8-installer oracle-java8-set-default

我尝试了AU Q&A方法,在添加PPA的第一步之后,出现了一个初始屏幕,其中包含其他信息。最有用的是在Debian系统上设置JRE 8的链接。

安装JRE 8的第三步要求您使用TabEnter接受许可协议。在安装过程中最繁重的部分,您的机器将暂停几分钟。

现在打开LibreOffice,然后选择工具 -> 选项 -> LibreOffice- > 高级并设置此屏幕:

LO JRE8高级Setup.png

单击以下选项:

  • 使用Java运行时环境
  • Oracle公司1.8.0_161
  • 启用宏录制(实验性)
  • 点击确定
  • 系统将要求您重新启动,单击“立即重新启动”。

LibreOffice Writer宏

该宏将读取整个文档,并:

  • 将字体名称更改为Ubuntu。
  • 如果标题1将字体大小设置为28
  • 否则,如果字体大小为18,则设置为22
  • 否则将字体大小设置为12

该宏将保存文档并退出Libreoffice Writer。

关闭对话框

保存文件,将出现以下对话框:

LO Writer关闭RTF dialog.png

关闭此消息,如屏幕所示。如果启用此选项,则宏可能无法正常运行。

宏内容

我花了几天时间尝试使用“工具”->“宏”->“记录宏”->“基本”来记录宏。乍一看似乎很有希望,但是录制的宏的行为却不一致,必须放弃以手写基本宏。在Stack Overflow中找到的帮助专家可以帮助我进行基本的基本编码。结果如下:

Sub ChangeAllFonts
    rem - Change all font names to Ubuntu.
    rem - If heading 1 set font size to 28
    rem - else if font size is 18 set to 22
    rem - else set font size to 12
    rem - The macro will save document and exit LibreOffice Writer.
    Dim oDoc As Object
    Dim oParEnum As Object, oPar As Object, oSecEnum As Object, oSec As Object
    Dim oFamilies As Object, oParaStyles As Object, oStyle As Object
    oDoc = ThisComponent
    oParEnum = oDoc.Text.createEnumeration()
    Do While oParEnum.hasMoreElements()
      oPar = oParEnum.nextElement()
      If oPar.supportsService("com.sun.star.text.Paragraph") Then
        oSecEnum = oPar.createEnumeration()
        Do While oSecEnum.hasMoreElements()
          oSec = oSecEnum.nextElement()
          If oSec.TextPortionType = "Text" Then
            If oSec.ParaStyleName = "Heading 1" Then
                rem ignore for now
            ElseIf oSec.CharHeight = 18 Then
                oSec.CharHeight = 22.0
            Else
                oSec.CharHeight = 12.0
            End If
          End If
        Loop
      End If
    Loop
    oFamilies = oDoc.getStyleFamilies()
    oParaStyles = oFamilies.getByName("ParagraphStyles")
    oStyle = oParaStyles.getByName("Heading 1")
    oStyle.setPropertyValue("CharHeight", 28.0)
    FileSave
    StarDesktop.terminate()
End Sub

rem Above subroutine is missing call to UbuntuFontName ()
rem also it is calling oStyle.setPropertyValue("CharHeight", 28.0)
rem which may cause problems. Will test. Also StarDesktop.terminate ()
rem is known to cause problems and will likely be reworked with a
rem a dialog box telling operator the program is finished and maybe
rem to press <Alt>+<F4>.

rem ========= Original code below for possible recycling ===========

Sub AllFonts
rem - change all font names to Ubuntu.
rem - If heading 1 set font size to 28
rem - else if font size is 18 set to 22
rem - else set font size to 12

rem The macro will save document and exit Libreoffice Writer.

Dim CharHeight As Long, oSel as Object, oTC as Object
Dim CharStyleName As String
Dim oParEnum as Object, oPar as Object, oSecEnum as Object, oSec as Object
Dim oVC as Object, oText As Object
Dim oParSection        'Current Section

oText = ThisComponent.Text
oSel = ThisComponent.CurrentSelection.getByIndex(0) 'get the current selection
oTC = oText.createTextCursorByRange(oSel)           ' and span it with a cursor

rem Scan the cursor range for chunks of given text size.
rem (Doesn't work - affects the whole document)

oParEnum = oTC.Text.createEnumeration()
Do While oParEnum.hasMoreElements()
  oPar = oParEnum.nextElement()
  If oPar.supportsService("com.sun.star.text.Paragraph") Then
    oSecEnum = oPar.createEnumeration()
    oParSection = oSecEnum.nextElement()
    Do While oSecEnum.hasMoreElements()
      oSec = oSecEnum.nextElement()
      If oSec.TextPortionType = "Text" Then
        CharStyleName = oParSection.CharStyleName
        CharHeight = oSec.CharHeight
        if CharStyleName = "Heading 1" Then
            oSec.CharHeight = 28
        elseif CharHeight = 18 Then
            oSec.CharHeight = 22
        else
            oSec.CharHeight = 12
        End If
      End If
    Loop
  End If

Loop

FileSave
stardesktop.terminate()

End Sub


Sub UbuntuFontName
rem ----------------------------------------------------------------------
rem define variables
dim document   as object
dim dispatcher as object
rem ----------------------------------------------------------------------
rem get access to the document
document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")

rem ----------- Select all text ------------------------------------------
dispatcher.executeDispatch(document, ".uno:SelectAll", "", 0, Array())

rem ----------- Change all fonts to Ubuntu -------------------------------
dim args5(4) as new com.sun.star.beans.PropertyValue
args5(0).Name = "CharFontName.StyleName"
args5(0).Value = ""
args5(1).Name = "CharFontName.Pitch"
args5(1).Value = 2
args5(2).Name = "CharFontName.CharSet"
args5(2).Value = -1
args5(3).Name = "CharFontName.Family"
args5(3).Value = 0
args5(4).Name = "CharFontName.FamilyName"
args5(4).Value = "Ubuntu"

dispatcher.executeDispatch(document, ".uno:CharFontName", "", 0, args5())

end sub


sub FileSave
rem ----------------------------------------------------------------------
rem define variables
dim document   as object
dim dispatcher as object
rem ----------------------------------------------------------------------
rem get access to the document
document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")

rem ----------------------------------------------------------------------
dispatcher.executeDispatch(document, ".uno:Save", "", 0, Array())

end sub

2

这是使用Libre Office的一次性方法。这不是批处理,但可能有助于激发其他答案。

打开一个具有Ubuntu字体的rtf文件,H1为28磅,某些文本为12磅,另一些为18磅。

这是一个例子:

测试rtf

以下步骤将应用您的问题“ if font-size:18px {make it 22px}#现在所有字体大小为18px的文本为22px;”的更改。

单击菜单上的“编辑”→“查找和替换”,或CtrlH单击“其他选项”。单击“搜索”框,然后单击“属性”按钮,“字体大小”复选框,然后单击“格式”按钮,从最右侧的滚动框中选择18 pt。单击“替换为”框,然后单击“格式”按钮,然后从最右边的滚动框

查找替代

单击全部替换

更改的适用行是:

\ par \ pard \ plain \ s0 \ ql \ widctlpar \ hyphpar0 \ ltrpar \ cf1 \ kerning1 \ dbch \ af7 \ langfe1081 \ dbch \ af7 \ afs24 \ alang1081 \ loch \ f3 \ fs24 \ lang1033 \ ql \ widctlpar \ hyphpar0 \ ltrpar {\ rtlch \ ltrch \ loch \ fs36 \ loch \ f6

将fs36更改为fs44

唯一更改的其他字段是您可能想要或不希望更新的revtime字段:

{\ revtim \ yr2018 \ mo3 \ dy31 \ hr22 \ min19}

知道发生了什么变化为我们提供了一种开发批处理方法的模型。可能会记录一个在打开文档时执行此操作的宏,或者开发一个脚本来进行所需的更改。


1

RTF规范中,有一些很好的线索可以说明如何实现这一目标

这是我对问题的分析。

您猜想使用CLI来完成此操作似乎是最简单的方法,因为我还没有看到任何基于GUI的应用程序可以处理这种批量转换。看来您可以简单地修改标题:

标头具有以下语法:

<header>
    \rtf <charset> \deff? <fonttbl> <filetbl>? <colortbl>? <stylesheet>? <listtables>? <revtbl>?

Each of the various header tables should appear, if they exist, in the above order. Document properties can occur before and between the header tables. A property must be defined before being referenced. Specifically:

* The style sheet must occur before any style usage.

* The font table must precede any reference to a font.

* The \deff keyword must precede any text without an explicit reference to a font, because it specifies the font to use in such cases.

就个人而言,在查看此信息后,我发现您尝试执行的所有操作看起来像标题中所支持的,从字体选择到样式。

有一些工具可以帮助您完成此过程,下面将概述这些工具,因为我没有您所拥有的文档样式的示例,也没有您想要的文档样式,并且更通用的答案可能比社区更有用一种针对您的实际情况。

grep将有助于解析要转换的现有文件以及现有样式<fonttbl>
<stylesheet>选择样式的目标样式示例。确定了实际拥有的内容之后,您应该能够编写一个简单的脚本来利用sed所需的标头内容替换现有的标头内容。如果您不熟悉bash脚本中的文件(示例)以及如何免费使用sed(示例),则有很多示例。

还有一个行选项可以替换文件中的字符串。根据您的用例,某些方法可能比其他方法更好。根据文件内容的不同,简单地将每个实例替换为正在使用的shell可能也可能没有意义fs36fs44这也可能与如何最好地编写表达式有关。根据文档的复杂性和内容,最好使用sedperl或者grep甚至结合使用它们。由于这已成为编程问题,因此最好向您推荐/programming/15402770/how-to-grep-and-replace,您将轻松找到1/2多种不同的方法,其中一种这很可能完全适合您的需求。

例如,如果您希望在系统范围内应用这些更改,

find /path/to/files -type f -exec sed -i 's/oldstring/newstring/g' {} \;rezizter提供可能是最好的。

如果您希望将更改包含在单个目录中,

grep -rl matchstring somedir/ | xargs sed -i 's/fs36/fs44/g'Billtian提供是一个很好的选择。

为了安全起见,您应该对文件进行预处理,以确保所做的任何更改都不会带来意想不到的后果。例如:

<!-- language: lang-bash -->

    #!/bin/bash
    for f in *.rtf 
        do
        echo $f
        grep fs36
        done

上面将显示目录中每个.rtf文件的包含搜索字符串fs36的行。

编辑:

可以在此处获得最新的规格我看不到任何会影响这种方法的更改。


1
您好,谢谢您首先介绍CLI解决方案。请分享一个代码示例,说明如何rtf使用标题和更改,sed这样答案将集中在sed
JohnDoea

@JohnDoea一直渴望帮助。希望您和将来的用户都觉得它有用。
年长者怪胎'18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.