Browse Source

Correction de plusieurs soucis sur la fonction nettoyer_raccourcis_typo() .

Cette fonction est utilisée par couper() ou pour calculer des attributs title 
ou encore pour indexer des documents par le plugin Indexer sur une base Sphinx.

C'est dans ce dernier cadre que quelques problèmes se sont montrées :

- la regexp qui supprimait les notes pouvait tuer PCRE si le texte était volumineux et avait des notes mal fermées.
On simplifie cette expression. Cela ne provoque aucun changement sur les bases de tests que j’ai pu voir, améliorant
même le retour de 3 articles qui renvoyaient vide avant à tord.

- contrairement à ce qu’affirmait le commentaire, les tableaux n’étaient pas supprimés dans la plupart des cas.
Effectivement la regexp cherchait uniquemnet des \r (sauts de paragraphe à cet endroit) et pas de \n (sauts de lignes à cet endroit).
La regexp n’étant pas multiligne d’une part et textwheel sachant bien gérer les tableaux même s’il n’y a pas de ligne vide avant/après,
on permet d’éliminer simplement les lignes de tableau en ajoutant \n à cet endroit.

Plus généralement cette fonction… ne nettoyait pas tous les raccourcis. Une partie était faite par couper() uniquement.
Il me semble que c'est un tord. On déplace donc de couper() dans la fonction nettoyer_raccourcis_typo() quelques nettoyages,
notamment la suppression des caractères de liste.

- les listes étaient retournées avec un saut de paragraphe entre chaque élément. Dans le cadre de ces fonctions ce n’est a priori pas utile,
et on retourne du coup un simple saut de ligne à la place (note: couper remplace les sauts de ligne par des espaces ensuite — pas les sauts de paragraphe).
Il y a donc un changement de comportement de ce point de vue.

- le texte de sortie est trimmé (couper() s’en occupe aussi d’ailleurs).

Conséquence notable pour Indexer : le contenu des tableau n’est plus retourné. Une option devrait être proposée à cette fonction
pour retourner les contenus des tableaux, mais sans les | .

On ajoute quelques fonctions de tests unitaires au passage.
La fonction couper() du core va être modifiée en conséquence.
svn/root/tags/plugins/textwheel/1.5.0
marcimat@rezo.net 4 years ago
parent
commit
c4ae426e30
  1. 5
      .gitattributes
  2. 35
      inc/lien.php
  3. 9
      tests/simpletest/all_tests.php
  4. 177
      tests/simpletest/data_test_typo.inc
  5. 12
      tests/simpletest/lanceur_spip.php
  6. 26
      tests/simpletest/nettoyer_raccourcis_typo.php
  7. 152
      tests/simpletest/nettoyer_raccourcis_typo_old.php

5
.gitattributes

@ -303,6 +303,11 @@ tests/data/typo/unordered_list.html -text
tests/data/typo/unordered_list.txt -text
tests/data/typo/whitespace.html -text
tests/data/typo/whitespace.txt -text
tests/simpletest/all_tests.php -text
tests/simpletest/data_test_typo.inc -text
tests/simpletest/lanceur_spip.php -text
tests/simpletest/nettoyer_raccourcis_typo.php -text
tests/simpletest/nettoyer_raccourcis_typo_old.php -text
tests/squelettes/modeles/textwheel_block.html -text
tests/squelettes/modeles/textwheel_inline.html -text
tests/tw_propre.php -text

35
inc/lien.php

@ -340,12 +340,31 @@ function expanser_un_lien($reg, $quoi = 'echappe', $env = null) {
}
}
// Meme analyse mais pour eliminer les liens
// et ne laisser que leur titre, a expliciter si ce n'est fait
// https://code.spip.net/@nettoyer_raccourcis_typo
/**
* Nettoie un texte en enlevant les raccourcis typo, sans les traiter
*
* On ne laisse que les titres des liens, en les explicitant si ce n’est pas fait.
*
* @param string $texte
* @param string $connect
* @return string
*/
function nettoyer_raccourcis_typo($texte, $connect = '') {
$texte = pipeline('nettoyer_raccourcis_typo', $texte);
// on utilise les \r pour passer entre les gouttes
$texte = str_replace("\r\n", "\n", $texte);
$texte = str_replace("\r", "\n", $texte);
// sauts de ligne et paragraphes
$texte = preg_replace("/\n\n+/", "\r", $texte);
// supprimer les traits, lignes etc
$texte = preg_replace("/(^|\r|\n)(-[-#\*]*\s?|_ )/", "\n", $texte);
// travailler en accents charset
$texte = unicode2charset(html2unicode($texte, true /* secure */ ));
if (preg_match_all(_RACCOURCI_LIEN, $texte, $regs, PREG_SET_ORDER)) {
include_spip('inc/texte');
foreach ($regs as $reg) {
@ -375,13 +394,19 @@ function nettoyer_raccourcis_typo($texte, $connect = '') {
$texte = preg_replace(_RACCOURCI_ANCRE, "", $texte);
// supprimer les notes
$texte = preg_replace(",[[][[]([^]]|[]][^]])*[]][]],UimsS", "", $texte);
$texte = preg_replace(",\[\[.*\]\],UimsS", "", $texte);
// supprimer les codes typos
$texte = str_replace(array('}', '{'), '', $texte);
// supprimer les tableaux
$texte = preg_replace(",(^|\r)\|.*\|\r,s", "\r", $texte);
$texte = preg_replace(",(?:^|\r|\n)\|.*\|(?:\r|\n|$),s", "\r", $texte);
// indiquer les sauts de paragraphes
$texte = str_replace("\r", "\n\n", $texte);
$texte = str_replace("\n\n+", "\n\n", $texte);
$texte = trim($texte);
return $texte;
}

9
tests/simpletest/all_tests.php

@ -0,0 +1,9 @@
<?php
require_once('lanceur_spip.php');
class AllTests_textwheel extends SpipTestSuite {
function __construct() {
parent::__construct('Tests Textwheel');
$this->addDir(__FILE__);
}
}

177
tests/simpletest/data_test_typo.inc

@ -0,0 +1,177 @@
<?php
trait Data_test_typo {
protected function _printTest(array $data, $nettoyer, $couper) {
$titre = isset($data['titre']) ? $data['titre'] : '';
if (!$this->assertEqual($nettoyer, $data['nettoyer'])) {
$this->reporter->paintFormattedMessage("Nettoyer_raccourcis_typo | $titre. Texte -> Attendu -> Reçu");
$this->reporter->paintFormattedMessage($data['texte']);
$this->reporter->paintFormattedMessage($data['nettoyer']);
$this->reporter->paintFormattedMessage($nettoyer);
}
if (!$this->assertEqual($couper, $data['couper'])) {
$this->reporter->paintFormattedMessage("Couper | $titre. Texte -> Attendu -> Reçu");
$this->reporter->paintFormattedMessage($data['texte']);
$this->reporter->paintFormattedMessage($data['couper']);
$this->reporter->paintFormattedMessage($couper);
}
}
function testNettoyerItalique(){
$this->_testData([[
'texte' => 'Un mot {italique}',
'couper' => 'Un mot italique',
'nettoyer' => 'Un mot italique',
],[
'texte' => '{Un texte italique}',
'couper' => 'Un texte italique',
'nettoyer' => 'Un texte italique',
]]);
}
function testNettoyerGras(){
$this->_testData([[
'texte' => 'Un mot {{gras}}',
'couper' => 'Un mot gras',
'nettoyer' => 'Un mot gras',
],[
'texte' => '{{Un texte gras}}',
'couper' => 'Un texte gras',
'nettoyer' => 'Un texte gras',
]]);
}
function testNettoyerIntertitre(){
$this->_testData([[
'texte' => '{{{Un intertitre}}}',
'couper' => 'Un intertitre',
'nettoyer' => 'Un intertitre',
],[
'texte' => "Ligne\n\n{{{Un intertitre}}}\n\nLigne",
'couper' => "Ligne\n\nUn intertitre\n\nLigne",
'nettoyer' => "Ligne\n\nUn intertitre\n\nLigne",
]]);
}
function testNettoyerLiens(){
$this->_testData([[
'texte' => 'Un lien [interne->article1]',
'couper' => 'Un lien interne',
'nettoyer' => 'Un lien interne',
],[
'texte' => 'Un lien [externe->http://example.org]',
'couper' => 'Un lien externe',
'nettoyer' => 'Un lien externe',
]]);
}
/**
* Les listes sont mises à plat
* 1 saut de ligne \n entre chaque, couper les réassemble en espace.
*
* @note
* Avant SPIP 3.2, 1 saut de paragraphe \n\n entre chaque (couper le laissait).
*/
function testNettoyerListes(){
$this->_testData([[
'texte' =>
"Une liste
-* un
-* deux
-* trois
",
'couper' => "Une liste un deux trois",
'nettoyer' => "Une liste\nun\ndeux\ntrois",
],[
'texte' =>
"Une liste avec ligne
-* un
-* deux
-* trois
",
'couper' => "Une liste avec ligne un deux trois",
'nettoyer' => "Une liste avec ligne\nun\ndeux\ntrois",
]]);
}
/**
* Les tableaux sont totalement supprimés.
* Enfin presque : remplacés par \n\n
* Le texte étant trimmé, \n en fins sont enlevés.
*
* @note
* Avant SPIP 3.2, les tableaux nétaient pas toujours correctement supprimés
*/
function testNettoyerTableaux(){
$this->_testData([[
// tableau sans sauts de ligne avant / après.
'titre' => 'tableau sans sauts de ligne avant / après',
'texte' =>
"| {{colonneA}} | {{colonneB}} |
| ligneA1 | ligneB1 |
| ligneA2 | ligneB2 |",
'couper' => "",
'nettoyer' => "",
],[
'texte' =>
"Un tableau sans ligne vide avant
| {{colonneA}} | {{colonneB}} |
| ligneA1 | ligneB1 |
| ligneA2 | ligneB2 |
",
'couper' => "Un tableau sans ligne vide avant",
'nettoyer' => "Un tableau sans ligne vide avant",
],[
'texte' =>
"Un tableau avec ligne vide avant
| {{colonneA}} | {{colonneB}} |
| ligneA1 | ligneB1 |
| ligneA2 | ligneB2 |
",
'couper' => "Un tableau avec ligne vide avant",
'nettoyer' => "Un tableau avec ligne vide avant",
],[
'texte' =>
"Un tableau avec ligne avant / après
| {{colonneA}} | {{colonneB}} |
| ligneA1 | ligneB1 |
| ligneA2 | ligneB2 |
Après
",
'couper' => "Un tableau avec ligne avant / après\n\nAprès",
'nettoyer' => "Un tableau avec ligne avant / après\n\nAprès",
]]);
}
/**
* Les notes sont supprimées.
*
* @note
* Avant 3.2 la regexp pouvait tuer pcre sur des textes longs
* ayant des notes mal fermées.
*/
function testNettoyerNotes(){
$this->_testData([[
'texte' => 'Une note bien fermée [[note 1]]',
'couper' => 'Une note bien fermée',
'nettoyer' => 'Une note bien fermée',
],[
'texte' => 'Une note mal fermée [[note 1]',
'couper' => 'Une note mal fermée [[note 1]',
'nettoyer' => 'Une note mal fermée [[note 1]',
],[
'texte' => 'Un lien dans une note [[note [lien->article1]]]',
'couper' => 'Un lien dans une note',
'nettoyer' => 'Un lien dans une note',
],[
'texte' => 'Lien et note ratée [[note [lien->article1]] ]',
'couper' => 'Lien et note ratée [[note lien] ]',
'nettoyer' => 'Lien et note ratée [[note lien] ]',
]]);
}
}

12
tests/simpletest/lanceur_spip.php

@ -0,0 +1,12 @@
<?php
/**
* Démarre SPIP afin d'obtenir ses fonctions depuis
* les jeux de tests unitaires de type simpletest
*/
$remonte = '../';
while (!is_dir($remonte . 'ecrire')) {
$remonte = "../$remonte";
}
require $remonte . 'tests/test.inc';
demarrer_simpletest();

26
tests/simpletest/nettoyer_raccourcis_typo.php

@ -0,0 +1,26 @@
<?php
require_once('lanceur_spip.php');
require_once('data_test_typo.inc');
class Test_nettoyer_raccourcis_typo extends SpipTest {
use Data_test_typo;
public function __construct() {
parent::__construct("Tests de nettoyer_raccourcis_typo()");
include_spip('inc/lien');
include_spip('inc/texte_mini');
}
/**
* @param array[] $data Collection of array with keys : [texte, couper, nettoyer]
*/
protected function _testData(array $data) {
foreach ($data as $d) {
$nettoyer = nettoyer_raccourcis_typo($d['texte']);
$couper = couper($d['texte']);
$this->_printTest($d, $nettoyer, $couper);
}
}
}

152
tests/simpletest/nettoyer_raccourcis_typo_old.php

@ -0,0 +1,152 @@
<?php
require_once('lanceur_spip.php');
require_once('data_test_typo.inc');
class Test_nettoyer_raccourcis_typo_old extends SpipTest {
use Data_test_typo;
public function __construct() {
parent::__construct("Tests de nettoyer_raccourcis_typo() anciens");
include_spip('inc/lien');
include_spip('inc/texte_mini');
}
protected function _testData(array $data) {
foreach ($data as $d) {
$nettoyer = static::nettoyer_raccourcis_typo_old($d['texte']);
$couper = static::couper_old($d['texte']);
$this->_printTest($d, $nettoyer, $couper);
}
}
public static function nettoyer_raccourcis_typo_old($texte, $connect = '') {
$texte = pipeline('nettoyer_raccourcis_typo', $texte);
if (preg_match_all(_RACCOURCI_LIEN, $texte, $regs, PREG_SET_ORDER)) {
include_spip('inc/texte');
foreach ($regs as $reg) {
list($titre, , ) = traiter_raccourci_lien_atts($reg[1]);
if (!$titre) {
$match = typer_raccourci($reg[count($reg) - 1]);
if (!isset($match[0])) {
$match[0] = '';
}
@list($type, , $id, , , , ) = $match;
if ($type) {
$url = generer_url_entite($id, $type, '', '', true);
if (is_array($url)) {
list($type, $id) = $url;
}
$titre = traiter_raccourci_titre($id, $type, $connect);
}
$titre = $titre ? $titre['titre'] : $match[0];
}
$titre = corriger_typo(supprimer_tags($titre));
$texte = str_replace($reg[0], $titre, $texte);
}
}
// supprimer les ancres
$texte = preg_replace(_RACCOURCI_ANCRE, "", $texte);
// supprimer les notes
$texte = preg_replace(",[[][[]([^]]|[]][^]])*[]][]],UimsS", "", $texte);
// supprimer les codes typos
$texte = str_replace(array('}', '{'), '', $texte);
// supprimer les tableaux
$texte = preg_replace(",(^|\r)\|.*\|(\r),s", "\r", $texte);
return $texte;
}
public static function couper_old($texte, $taille = 50, $suite = '&nbsp;(...)') {
if (!($length = strlen($texte)) or $taille <= 0) {
return '';
}
$offset = 400 + 2 * $taille;
while ($offset < $length
and strlen(preg_replace(",<(!--|\w|/)[^>]+>,Uims", "", substr($texte, 0, $offset))) < $taille) {
$offset = 2 * $offset;
}
if ($offset < $length
&& ($p_tag_ouvrant = strpos($texte, '<', $offset)) !== null
) {
$p_tag_fermant = strpos($texte, '>', $offset);
if ($p_tag_fermant && ($p_tag_fermant < $p_tag_ouvrant)) {
$offset = $p_tag_fermant + 1;
} // prolonger la coupe jusqu'au tag fermant suivant eventuel
}
$texte = substr($texte, 0, $offset); /* eviter de travailler sur 10ko pour extraire 150 caracteres */
// on utilise les \r pour passer entre les gouttes
$texte = str_replace("\r\n", "\n", $texte);
$texte = str_replace("\r", "\n", $texte);
// sauts de ligne et paragraphes
$texte = preg_replace("/\n\n+/", "\r", $texte);
$texte = preg_replace("/<(p|br)( [^>]*)?" . ">/", "\r", $texte);
// supprimer les traits, lignes etc
$texte = preg_replace("/(^|\r|\n)(-[-#\*]*|_ )/", "\r", $texte);
// travailler en accents charset
$texte = unicode2charset(html2unicode($texte, /* secure */
true));
if (!function_exists('nettoyer_raccourcis_typo')) {
include_spip('inc/lien');
}
$texte = static::nettoyer_raccourcis_typo_old($texte);
// supprimer les tags
$texte = supprimer_tags($texte);
$texte = trim(str_replace("\n", " ", $texte));
$texte .= "\n"; // marquer la fin
// corriger la longueur de coupe
// en fonction de la presence de caracteres utf
if ($GLOBALS['meta']['charset'] == 'utf-8') {
$long = charset2unicode($texte);
$long = spip_substr($long, 0, max($taille, 1));
$nbcharutf = preg_match_all('/(&#[0-9]{3,6};)/S', $long, $matches);
$taille += $nbcharutf;
}
// couper au mot precedent
$long = spip_substr($texte, 0, max($taille - 4, 1));
$u = $GLOBALS['meta']['pcre_u'];
$court = preg_replace("/([^\s][\s]+)[^\s]*\n?$/" . $u, "\\1", $long);
$points = $suite;
// trop court ? ne pas faire de (...)
if (spip_strlen($court) < max(0.75 * $taille, 2)) {
$points = '';
$long = spip_substr($texte, 0, $taille);
$texte = preg_replace("/([^\s][\s]+)[^\s]*\n?$/" . $u, "\\1", $long);
// encore trop court ? couper au caractere
if (spip_strlen($texte) < 0.75 * $taille) {
$texte = $long;
}
} else {
$texte = $court;
}
if (strpos($texte, "\n")) // la fin est encore la : c'est qu'on n'a pas de texte de suite
{
$points = '';
}
// remettre les paragraphes
$texte = preg_replace("/\r+/", "\n\n", $texte);
// supprimer l'eventuelle entite finale mal coupee
$texte = preg_replace('/&#?[a-z0-9]*$/S', '', $texte);
return quote_amp(trim($texte)) . $points;
}
}
Loading…
Cancel
Save