web-dev-qa-db-fra.com

Modifier 2 ou plusieurs documents LibreOffice pour qu'ils aient exactement le même style / formatage

Supposons que j'ai un répertoire contenant environ 100 fichiers .rtf que je modifie avec LibreOffice Writer.

Je souhaite que tous les fichiers de ce répertoire aient exactement les mêmes directives de style de texte enrichi, par exemple:

* 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;

Et ainsi de suite ... Donc, fondamentalement, je veux changer tous les fichiers en même temps. Un tel "style en vrac" est-il possible?

Peut-être que c'est possible avec le CLI en quelque sorte?

14
JohnDoea

Utiliser les outils Libreoffice au lieu de la CLI

Lorsque tout ce que vous avez est un outil de ligne de commande, tout ressemble à un problème de ligne de commande. J'ai décidé d'écrire cette réponse à l'aide de macros LibreOffice:

  1. Utilisez une boucle de ligne de commande pour traiter chaque document Writer dans un environnement "sans en-tête".
  2. Exécutez la macro pour modifier le fichier de document Writer .rtf (Rich Text Format).
  3. Macro enregistre le fichier et quitte
  4. Boucle de retour à 1.

Créer des données de test

Créez deux fichiers ou plus contenant:

richtext2.png

Créez le script ~/Downloads/copy-rtf.sh contenant:

cp ~/Documents/*.rtf ~/Downloads

Marquer comme exécutable en utilisant

chmod a+x ~/Downloads/copy-rtf.sh
  • Pendant le développement et les tests, les macros modifiant les fichiers *.rtf seront exécutées dans le répertoire ~/Downloads.
  • Avant chaque test, tapez cd ~/Downloads et exécutez ./copy-rtf.sh
  • Une fois que la sortie est parfaite, ils sont copiés dans le répertoire actif.

Le répertoire Téléchargements est utilisé pour les raisons suivantes:

  • tout le monde a un ~/Downloads
  • il est ajouté régulièrement et manuellement vidé périodiquement
  • il est plus permanent que le répertoire /tmp/ qui peut ne pas persister après les redémarrages.

Exécuter une macro dans un environnement sans tête

En utilisant ceci réponse Stack Exchange , appelez Libreoffice Writer à partir de la ligne de commande et transmettez-lui un nom de macro global à exécuter:

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

La réponse ci-dessus peut ne pas fonctionner de la sorte ne autre méthode peut être essayée:

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

Installer Java Environnement d'exécution

Pour exécuter des macros, vous devez disposer de Java Environnement d'exécution (JRE). La page Web du développeur contient instructions pour le téléchargement et l’installation manuelle.

Cependant, ce Q & A de l'UA: https://askubuntu.com/a/728153/30752 suggère qu'il est aussi simple que:

Sudo apt-add-repository ppa:webupd8team/Java
Sudo apt-get update
Sudo apt-get install Oracle-Java8-installer Oracle-Java8-set-default

J'ai essayé la méthode de questions et réponses de l'UA et après la première étape de l'ajout du PPA, un écran de démarrage apparaît avec des informations supplémentaires. Le plus utile est un lien vers configuration de JRE 8 sur les systèmes Debian .

La troisième étape de l’installation de JRE 8 nécessite l’utilisation de Tab et Enter accepter le contrat de licence. Votre machine s'interrompra quelques minutes au cours de la partie la plus lourde de la procédure d'installation.

Ouvrez maintenant LibreOffice et sélectionnez Outils -> Options -> LibreOffice -> Avancé et configurez cet écran:

LO JRE8 Advanced Setup.png

Cliquez sur les options pour:

  • Utiliser un environnement d'exécution Java
  • Oracle Corporation 1.8.0_161
  • Activer l'enregistrement de macros (expérimental)
  • Cliquez sur OK
  • Vous serez invité à redémarrer, cliquez sur "Redémarrer maintenant".

Macro Writer LibreOffice

La macro lira l’ensemble du document et:

  • changer le nom de la police pour Ubuntu.
  • Si le titre 1 définit la taille de la police à 28
  • sinon, si la taille de la police est 18, régler sur 22
  • sinon définir la taille de la police à 12

La macro enregistrera le document et quittera Libreoffice Writer.

Désactiver le dialogue

Faites une sauvegarde de fichier et cette boîte de dialogue apparaît:

LO Writer turn off RTF dialog.png

Désactivez ce message comme indiqué à l'écran. La macro peut ne pas fonctionner correctement si cette option est activée.

Contenu de la macro

J'ai passé quelques jours à essayer d'enregistrer une macro en utilisant "Outils" -> "Macros" -> "Enregistrer une macro" -> "Basique". Au début, cela semblait prometteur, mais la macro enregistrée avait un comportement incohérent et devait être abandonnée pour une macro de base écrite à la main. Une aide trouvée dans Stack Overflow pour un expert là-bas pour m'aider avec la base codage de base . Voici le résultat:

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
5
WinEunuuchs2Unix

Voici une approche ponctuelle utilisant Libre Office. Ce n'est pas un lot, mais cela peut inspirer d'autres réponses.

Ouvrez un fichier rtf contenant la police Ubuntu, H1 à 28 points, du texte à 12 points et d’autres à 18 points.

Voici un exemple:

test rtf

Les étapes suivantes appliqueront la modification demandée dans votre question "si la taille de la police: 18px {la rendre 22px} # # tout le texte avec la taille de la police 18px est maintenant 22px;"

Cliquez sur Édition → Rechercher et remplacer dans le menu ou appuyez sur CtrlH Autres options Cliquez sur la boîte de recherche puis sur le bouton d'attributs Taille de la police, puis sur le bouton Format, puis sélectionnez 18 pt dans la zone de défilement extrême droite. Cliquez sur Remplacer par une case, puis le bouton Format et sélectionnez 22 pt dans la zone de défilement extrême droite.

FindNreplace

Cliquez sur Remplacer tout

la ligne applicable qui a changé était:

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

le fs36 changé en fs44

le seul autre champ qui a changé est le champ revtime que vous ne souhaitez peut-être pas mettre à jour:

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

Savoir ce qui a changé nous fournit un modèle pour développer une approche par lots. Il est probablement possible d'enregistrer une macro qui le fait lors de l'ouverture d'un document ou de développer un script qui apporte les modifications souhaitées.

2
Elder Geek

Il existe de très bons indices sur la manière dont on pourrait s'y prendre dans la spécification RTF.

Voici mon analyse de la question.

Accomplir ceci en utilisant la CLI comme vous le supposez semble être l'approche la plus simple car je n'ai vu aucune application à interface graphique pouvant gérer ce type de conversion par lots. Il semble que vous puissiez simplement modifier l'en-tête:

L'en-tête a la syntaxe suivante:

<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.

Personnellement, à la lecture de ces informations, je me rends compte que tout ce que vous essayez de faire semble être pris en charge dans l’en-tête, de la sélection de police à style.

Il existe des outils pour vous aider dans ce processus que je décrirai ci-dessous comme suit: Je n'ai pas d'exemple de style de document ni de style de document que vous souhaitez et une réponse plus générique sera probablement plus utile à la communauté qu’une réponse à votre situation exacte.

grepsera utile pour analyser les fichiers existants à convertir et un exemple du style cible pour <fonttbl> existant et
<stylesheet> sélections. Une fois que vous avez déterminé ce que vous avez réellement, vous devriez être capable d’écrire un script simple utilisant sedpour remplacer le contenu de l’en-tête existant par le contenu de l’en-tête souhaité. Il existe de nombreux exemples illustrant comment parcourir des fichiers dans un script bash ( exemple ) et comment utiliser sed ( exemple ) disponible gratuitement si vous n'êtes pas familiarisé avec ces concepts.

Il existe également des options d'une ligne pour remplacer une chaîne dans un fichier. Certains peuvent fonctionner mieux que d'autres, selon votre cas d'utilisation. En fonction du contenu de vos fichiers, il peut être judicieux de remplacer simplement chaque instance de fs36 par fs44. Le shell que vous utilisez peut également avoir une incidence sur la meilleure façon d'écrire vos expressions. En fonction de la complexité et du contenu de vos documents, il peut être préférable d'utiliser sedname__, Perlou grepou même une combinaison de ceux-ci. Comme cela est devenu une question de programmation, il est préférable de vous renvoyer https://stackoverflow.com/questions/15402770/how-to-grep-and-replace où vous trouverez facilement un 1/2 douzaines d’approches différentes, dont l’une est parfaitement adaptée à vos besoins.

Par exemple, si vous souhaitez appliquer ces modifications à l’ensemble du système,

find /path/to/files -type f -exec sed -i 's/oldstring/newstring/g' {} \; tel que fourni par rezizter Est probablement le meilleur.

Si vous souhaitez contenir vos modifications dans un seul répertoire,

grep -rl matchstring somedir/ | xargs sed -i 's/fs36/fs44/g'as fourni par billtian est un excellent choix.

Pour plus de sécurité, vous devez prétraiter les fichiers pour vous assurer que les modifications que vous apporterez n'auront pas de conséquences inattendues. Par exemple:

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

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

Ce qui précède affichera les lignes contenant la chaîne de recherche fs36 pour chaque fichier .rtf du répertoire.

Modifier:

La spécification la plus récente peut être obtenue ici. Je ne vois aucun changement susceptible d'influencer cette approche.

1
Elder Geek