Convertire un documento RTF in testo in PHP

rtf2txt

Per convertire un file da RTF a PHP bastano poche sostituzioni, visto che l’RTF ha una sintassi di solo testo.
Negli esempi succesivi in $rtf è racchiuso tutto il file RTF.

Iniziamo con il rimuovere le intestazioni del file. Niente di più facile, le intestazioni finiscono quando inizia il primo paragrafo!

$text = substr($rtf, strpos($rtf, '\par '));

Ora dobbiamo solamente sostituire i caratteri speciali (come le lettere accentate) che in rtf hanno una loro sintassi. Creiamo un array per le conversioni:

$special = array('e1'=>'á', 'c0'=>'À', 'e0'=>'à', 'c9'=>'É', 'e9'=>'é', 'c8'=>'È', 'e8'=>'è', 'cd'=>'Í', 'ed'=>'í', 'cc'=>'Ì', 'ec'=>'ì', 'd3'=>'Ó', 'f3'=>'ó', 'd2'=>'Ò', 'f2'=>'ò', 'da'=>'Ú', 'fa'=>'ú', 'd9'=>'Ù', 'f9'=>'ù', '80'=>'€', 'd1'=>'Ñ', 'f1'=>'ñ', 'c7'=>'Ç', 'e7'=>'ç', 'dc'=>'Ü', 'fc'=>'ü', 'bf'=>'¿', 'a1'=>'¡', 'b7'=>'·', 'a9'=>'©', 'ae'=>'®', 'ba'=>'º', 'aa'=>'ª', 'b2'=>'²', 'b3'=>'³');

Bene, ora possiamo convertirli ricercando nel testo ogni entità e sostituendola con il rispettivo carattere. Sapendo che ogni tag di rtf inizia con \ ed ha 2 caratteri l’espressione regolare di ricerca è semplicissima:

   foreach($special as $key => $val){
      $text = str_replace('\\\\'.$key, $val, $text);
   }

Ora dobbiamo rimuovere tutti i tag. Anche questo si fa con una semplice espressione regolare molto simile alla precedente. Inoltre bisogna eliminare anche i tag di apertura e chiusura, ma questi sono semplicemente racchiusi da { e } e quindi basta rimuovere le parentesi grafe

$text = preg_replace('/'.preg_quote('\\').'[a-z0-9]+/', '', $text);
$text = str_replace('}{', '', $text);

Ora si effettua la pulizia finale, rimuovendo tutti quei tag sfuggiti ai controlli precedenti

$text = substr($text, strpos($text,'*')-1, -2);
$text = preg_replace('/ {2,}/', ' ', $text);

Bene, ora nella variabile $text abbiamo il nostro file RTF convertito in testo!

Utilizzando tutta la descrizione qui sopra si ricava questa semplice funzioncina:

/**
 *
 * Converte un file RTF in una stringa
 *
 * @author     Giulio "Chalda" Bettega
 * @license    http://opensource.org/licenses/gpl-license.php GNU Public License
 * @link       https://blog.chalda.it/convertire-un-documento-rtf-in-testo-in-php-10.html
 * @param      string  $filename  L'url
 * @return     string  Il file convertito in testo semplice
 *
 */
function rtf2txt($filename){

   // Recupero il file
   $handle = fopen($filename, "r");
   $rtf = fread($handle, filesize($filename));
   fclose($handle);

   // Tolgo le intestazioni
   $text = substr($rtf, strpos($rtf, '\par '));

   // Converto i caratteri speciali
   $special = array('e1'=>'á', 'c0'=>'À', 'e0'=>'à', 'c9'=>'É', 'e9'=>'é', 'c8'=>'È', 'e8'=>'è', 'cd'=>'Í', 'ed'=>'í', 'cc'=>'Ì', 'ec'=>'ì', 'd3'=>'Ó', 'f3'=>'ó', 'd2'=>'Ò', 'f2'=>'ò', 'da'=>'Ú', 'fa'=>'ú', 'd9'=>'Ù', 'f9'=>'ù', '80'=>'€', 'd1'=>'Ñ', 'f1'=>'ñ', 'c7'=>'Ç', 'e7'=>'ç', 'dc'=>'Ü', 'fc'=>'ü', 'bf'=>'¿', 'a1'=>'¡', 'b7'=>'·', 'a9'=>'©', 'ae'=>'®', 'ba'=>'º', 'aa'=>'ª', 'b2'=>'²', 'b3'=>'³');
   foreach($special as $key => $val){
      $text = str_replace('\\\\'.$key, $val, $text);
   }

   // Rimuovo i tag
   $text = preg_replace('/'.preg_quote('\\').'[a-z0-9]+/', '', $text);
   $text = str_replace('}{', '', $text);

   // Pulizia finale
   $text = substr($text, strpos($text,'*')-1, -2);
   $text = preg_replace('/ {2,}/', ' ', $text);

   return $text;
}

Unisciti alla discussione

8 commenti

  1. Ti avviso che ereg dal php 5 è nella lista delle funzioni deprecate, quindi è preferibile utilizzare preg (è anche più veloce).
    Comunque grazie della funzione, mi serviva proprio!

  2. Splendida… mi ha dato un ottimo spunto per una cosa che serviva a me.. una conversione rapida (senza miliardi di file da includere) in html.. e mi sta riuscendo…
    Solo che (non so se è successo pure a te) nel file RTF convertito (anche in formato txt) restano degli spazi… ho provato ad aprire il file originale con notepad ed anche lì ci sono.
    Hai qualche idea di come “eliminarli”? sembrano essere a “fine riga” nel notepad… ma trattandosi di un file RTF… di fatto troncano una parola a metà, ed è un peccato perché lo fa anche nella versione txt.

    Mi spiego meglio… facendo fare solo “alcuni” dei passaggi al tuo script… gli spazi extra non arrivano da qui
    indossa}{ re }

    ma sono proprio già nel testo caricato…

    mo ndo fatato

    se hai un’idea….

  3. Ciao Marty, lieto di esserti stato utile 🙂
    Non ho capito benissimo la tua domanda quindi rispondo con 3 diverse soluzioni 😀

    Se fossero solamente spazi bianchi e caratteri di fine riga potresti usare una cosa del tipo:

       $text = preg_replace('/\s+/ms', ' ', $text);
    

    Se invece il problema sono le parentesi grafe ( tipo “indossa}{ re}” ) il problema è più complicato, ma penso si possa risolvere eliminando le parentesi graffe (tanto difficilmente sono presenti in un testo)

       $text = preg_replace('/([}{]+ )/ms', '', $text);
    

    Se invece gli spazi bianchi sono direttamente nel testo e non sono racchiusi da segnaposto, io controllerei per prima cosa se ci sono anche aprendo il file rtf;
    se non ci sono controllerei se effettivamente sono spazi (magari sono caratteri vuoti speciali, tipo il 255 nella tabella ASCII);
    Se invece ci sono anche aprendo il file con programmi tipo wordpad allora il problema diventa grande quanto la lunghezza del file: per file piccoli sostituzione a mano, per file molto grandi ricerca incrociata con un file dizionario 😛

    Spero di esserti stato utile in almeno uno dei 3 casi!

  4. Purtroppo credo caschiamo nel terzo caso.

    Se apro il file rtf con notepad…. ovviamente lo visualizzo su RIGHE diverse… beh… quell’esempio che ti ho riportato è uno di quelli.
    Scrivendo a casaccio… il risultato è questo

    ……………. … .. . … il mo
    ndo fatato…..

    Come vedi la parola mondo è troncata sulle due righe, diventa (analizzando) uno spazio nel testo. In effetti dovrei verificare se è un qualche carattere “speciale”… vedrò 😉

    In ogni caso grazie mille.

    Già che ci sono… (ti avviso che sono alle primissime armi con php, anche se faccio programmazione in assemler e C da una vita o due) sai per caso se è possibile “modificare” il subject in un preg_replace?
    Come ti dicevo io avevo necessità di prendere un file RTF semplice semplice e tradurlo in HMTL.
    Non mi serve una gran cosa perché massimo ho Bold e Corsivo da riconoscere, più qualche cambio dimensione del carattere… e proprio qui è il problema.

    $text = preg_replace(‘/\\\fs([0-9]+)/’, ”, $text);

    Questa cosa come vedi riconosce una sequenza specifica dell’rtf che è \fs seguita da due numeri che identificano la dimensione del carattere.
    $1 è il valore numerico definito nel pattern… fin qui tutto ok.
    Solo che dovrei dividerlo per due… è possibile farlo DIRETTAMENTE nel preg_replace? Una cosa tipo (osceno lo so… è per farmi capire)

    $text = preg_replace(‘/\\\fs([0-9]+)/’, ”, $text);

    Ovvio che come sopra NON funziona 😉 sai se si può fare????

    Saluti.

  5. Ops… essendo codice HTML l’ha troncato… sostituisco con delle quadre tanto per farmi capire.

    $text = preg_replace(‘/\\\fs([0-9]+)/’, ‘[span style=”font-size:$1px”;]’, $text);

    mi serve che $1 sia inserito come $1/2… ma come??
    Come sotto non può funzionare ovvio… ma non so se si può fare.

    $text = preg_replace(‘/\\\fs([0-9]+)/’, ‘[span style=”font-size:($1px/2)”;]’, $text);

  6. Per il problema dei spazi io proverei per prima cosa il primo codice che ti ho scritto nel commento precedente, magari sono solamente caratteri di fine riga che in rtf non vengono interpretati ma che chiaramente in formato testo si vedono :). Se non dovesse funzionare il primo codice che ti ho scritto nel commento precedente prova anche un

    $text = str_replace(array("\n","\r"),'', $text);
    

    Per la seconda domanda… Si, è possibile, basta utilizzare il comando preg_replace_callback, con cui si può specificare una funzione personale per la modifica:

     $text = preg_replace_callback(
            '‘/\\\fs([0-9]+)/',
            create_function(
                '$matches',
                'return "<span style=\"font-size:".($matches[1]/2)."px\";>";'
            ),
            $text
        );
    

    Prova a guardarti la guida sul comando 🙂

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *