Fix and improve LSformat PHP and JS implementations

This commit is contained in:
Benjamin Renard 2018-09-20 19:28:26 +02:00
parent 753a888bf2
commit a03b737de8
5 changed files with 234 additions and 95 deletions

View file

@ -2,7 +2,7 @@
<title>Format paramétrable</title> <title>Format paramétrable</title>
<para>Un <emphasis>format paramétrable</emphasis> est une chaîne de caractères <para>Un <emphasis>format paramétrable</emphasis> est une chaîne de caractères
contenant des mots clés formés comme dans l'exemple suivant&nbsp;: contenant des mots clés formés comme dans l'exemple suivant&nbsp;:
<programlisting linenumbering="unnumbered">%{[nom du mot clé][:A][:B][! ou _][~]}</programlisting> <programlisting linenumbering="unnumbered">%{[nom du mot clé][:A][:B][! ou _][~][%]}</programlisting>
Le nom du mot clé peut contenir des lettres de "a" à "z", de "A" à "Z" et des Le nom du mot clé peut contenir des lettres de "a" à "z", de "A" à "Z" et des
chiffres de 0 à 9. Ces mots clés seront remplacés par les valeurs passées en chiffres de 0 à 9. Ces mots clés seront remplacés par les valeurs passées en
paramètres et liées au contexte d'utilisation. Les paramètres <emphasis>:A</emphasis> et paramètres et liées au contexte d'utilisation. Les paramètres <emphasis>:A</emphasis> et
@ -32,9 +32,24 @@ dans le premier cas. Si <varname>B</varname> vaut zéro, la totalité de la long
de la chaîne sera retournée en tenant compte de <varname>A</varname> pour le rang de la chaîne sera retournée en tenant compte de <varname>A</varname> pour le rang
du premier caractère. du premier caractère.
</para> </para>
<para>Les paramètres <emphasis>!</emphasis> ou <emphasis>_</emphasis> permettre respectivement de forcer la mise en majuscule ou en minuscule de la valeur de substitution.</para> <para>Il existe par ailleurs des paramètres permettant de modifier la valeur de
substitution avant son utilisation :
<itemizedlist>
<listitem>
<simpara>Les paramètres <emphasis>!</emphasis> ou <emphasis>_</emphasis> permettre
respectivement de forcer la mise en majuscule ou en minuscule ;</simpara>
</listitem>
<para>Le paramètre <emphasis>~</emphasis> permet qu'en a lui de forcer la suppression des accents dans la valeur de substitution.</para> <listitem>
<simpara>Le paramètre <emphasis>~</emphasis> permet de forcer la suppression des
accents ;</simpara>
</listitem>
<listitem><simpara>Le paramètre <emphasis>%</emphasis> permet de protéger les
caractères éligibles en entités HTML.</simpara>
</listitem>
</itemizedlist>
</para>
<important><simpara>Lorsque qu'une seule valeur clé est disponible pour la <important><simpara>Lorsque qu'une seule valeur clé est disponible pour la
substitution, le nom du mot clé n'importe pas. Tous les mots clés trouvés dans substitution, le nom du mot clé n'importe pas. Tous les mots clés trouvés dans

View file

@ -40,19 +40,18 @@
function getFData($format,$data,$meth=NULL) { function getFData($format,$data,$meth=NULL) {
$unique=false; $unique=false;
/* /*
* Format : %{[key name][:A][:B][! ou _][~]} * Format : %{[key name][:A][:B][! ou _][~][%}}
* *
* Extracted fields * Extracted fields
* - 0 : full string '%{...}'
* - 1 : key name * - 1 : key name
* - 2 : :A * - 2 : :A
* - 3 : A * - 3 : A
* - 4 : :B * - 4 : :B
* - 5 : B * - 5 : B
* - 6 : "-" * - 6 : "!" / "_" / "~" / "%"
* - 7 : ! or _
* - 8 : ~
*/ */
$expr="/%[{(]([A-Za-z0-9]+)(\:(-?[0-9])+)?(\:(-?[0-9]+))?(-)?(\!|\_)?(~)?[})]/"; $expr="/%[{(]([A-Za-z0-9]+)(\:(-?[0-9])+)?(\:(-?[0-9]+))?([\!\_~%]*)[})]/";
if(!is_array($format)) { if(!is_array($format)) {
$format=array($format); $format=array($format);
$unique=true; $unique=true;
@ -130,42 +129,73 @@ function getFData($format,$data,$meth=NULL) {
} }
function _getFData_extractAndModify($data,$ch) { function _getFData_extractAndModify($data,$ch) {
if($ch[3]) { /*
if ($ch[5]) { * Format : %{[key name][:A][:B][-][! ou _][~][%}}
if ($ch[6]) { *
if ($ch[3]<0) { * Extracted fields
$s=strlen((string)$data)-(-1*$ch[3])-$ch[5]; * - 0 : full string '%{...}'
$l=$ch[5]; * - 1 : key name
} * - 2 : :A
else { * - 3 : A
$s=$ch[3]-$ch[5]; * - 4 : :B
$l=$ch[5]; * - 5 : B
if ($s<0) { * - 6 : "!" / "_" / "~" / "%"
$l=$l-(-1*$s); */
$s=0; // If A
} if($ch[3]!="") {
} // If A and B
} if ($ch[5]!="") {
else { // If A and B=0
$s=$ch[3]; if ($ch[5]==0) {
$l=$ch[5]; // If A<0 and B=0
}
}
else if ($ch[5]==0) {
if ($ch[3]<0) { if ($ch[3]<0) {
$s=strlen((string)$data)-(-1*$ch[3]); $s=strlen((string)$data)-(-1*$ch[3]);
$l=strlen((string)$data); $l=strlen((string)$data);
} }
// If A >= 0 and B
else { else {
$s=$ch[3]; $s=$ch[3];
$l=strlen((string)$data); $l=strlen((string)$data);
} }
} }
// If A and B > 0
elseif ($ch[5]>0) {
// If A < 0 and B > 0 or A >= 0 and B > 0
$s=$ch[3];
$l=$ch[5];
}
// If A and B < 0
else {
// If A < 0 and B < 0
if ($ch[3]<0) {
$s=$ch[5];
$l=false;
}
// If A >= 0 and B < 0
else {
$s=$ch[3]+$ch[5];
$l=abs($ch[5]);
}
}
}
// If only A
else {
if ($ch[3]<0) {
$s=$ch[3];
$l=false;
}
else { else {
$s=0; $s=0;
$l=$ch[3]; $l=$ch[3];
} }
$val=substr((string)$data,$s,$l); }
if ($l==false) {
$val=mb_substr((string)$data,$s);
}
else {
$val=mb_substr((string)$data,$s, abs($l));
}
} }
else { else {
try { try {
@ -176,17 +206,24 @@ function _getFData_extractAndModify($data,$ch) {
} }
} }
if ($ch[6]) {
# Without Accent # Without Accent
if ($ch[8]) { if (strpos($ch[6], '~')!==false) {
$val = withoutAccents($val); $val = withoutAccents($val);
} }
# Upper / Lower case # Upper / Lower case
if ($ch[7]=="!") { if (strpos($ch[6], '!')!==false) {
$val=strtoupper($val); $val=mb_strtoupper($val);
}
elseif (strpos($ch[6], '_')!==false) {
$val=mb_strtolower($val);
}
# Escape HTML entities
if (strpos($ch[6], '%')!==false) {
$val = htmlentities($val);
} }
elseif ($ch[7]=='_') {
$val=strtolower($val);
} }
return $val; return $val;
@ -194,7 +231,7 @@ function _getFData_extractAndModify($data,$ch) {
function getFieldInFormat($format) { function getFieldInFormat($format) {
$fields=array(); $fields=array();
$expr='/%[{(]([A-Za-z0-9]+)(\:(-?[0-9])+)?(\:(-?[0-9]+))?(-)?(\!|\_)?(~)?[})]/'; $expr='/%[{(]([A-Za-z0-9]+)(\:(-?[0-9])+)?(\:(-?[0-9]+))?(-)?(\!|\_)?(~)?(%)?[})]/';
while (preg_match($expr,$format,$ch)) { while (preg_match($expr,$format,$ch)) {
$fields[]=$ch[1]; $fields[]=$ch[1];
$format=str_replace($ch[0],'',$format); $format=str_replace($ch[0],'',$format);

View file

@ -44,7 +44,7 @@ function LSdebug(arguments) {
*/ */
function getFData(format,data,meth) { function getFData(format,data,meth) {
/* /*
* Format : %{[key name][:A][:B][! ou _][~]} * Format : %{[key name][:A][:B][! ou _][~][%]}
* *
* Extracted fields * Extracted fields
* - 1 : full string in %{} * - 1 : full string in %{}
@ -53,11 +53,9 @@ function getFData(format,data,meth) {
* - 4 : A * - 4 : A
* - 5 : :B * - 5 : :B
* - 6 : B * - 6 : B
* - 7 : "-" * - 7 : "!" / "_" / "~" / "%"
* - 8 : ! or _
* - 9 : ~
*/ */
var getMotif = new RegExp('%\{(([A-Za-z0-9]+)(\:(-?[0-9])+)?(\:(-?[0-9])+)?)(-)?(\!|\_)?(~)?\}'); var getMotif = new RegExp('%\{(([A-Za-z0-9]+)(\:(-?[0-9])+)?(\:(-?[0-9])+)?)([\!\_\~\%]*)?\}');
var find=1; var find=1;
var val=""; var val="";
if(($type(data)=='object') || ($type(data)=='array')) { if(($type(data)=='object') || ($type(data)=='array')) {
@ -95,7 +93,7 @@ function getFData(format,data,meth) {
val=_getFData_extractAndModify(val,ch); val=_getFData_extractAndModify(val,ch);
format=format.replace(new RegExp('%\{'+ch[1]+'[\:0-9\!\_\~\-]*\}'),val); format=format.replace(new RegExp('%\{'+ch[1]+'[\:0-9\!\_\%\~]*\}'),val);
} }
else { else {
find=0; find=0;
@ -108,7 +106,7 @@ function getFData(format,data,meth) {
var ch = getMotif.exec(format); var ch = getMotif.exec(format);
if ($type(ch)) { if ($type(ch)) {
val=_getFData_extractAndModify(data,ch) val=_getFData_extractAndModify(data,ch)
format=format.replace(new RegExp('%\{'+ch[1]+'[\:0-9\!\_\~\-]*\}'),val); format=format.replace(new RegExp('%\{'+ch[1]+'[\:0-9\!\_\%\~]*\}'),val);
} }
else { else {
find=0; find=0;
@ -119,64 +117,94 @@ function getFData(format,data,meth) {
} }
function _getFData_extractAndModify(data,ch) { function _getFData_extractAndModify(data,ch) {
console.log(ch); /*
var val=data; * Extracted fields
* - 1 : full string in %{}
* - 2 : key name
* - 3 : :A
* - 4 : A
* - 5 : :B
* - 6 : B
* - 7 : "!" / "_" / "~" / "%"
*/
var val=(' ' + data).slice(1);
// If A // If A
if($type(ch[4])) { if($type(ch[4])) {
ch[4]=parseInt(ch[4]); ch[4]=parseInt(ch[4]);
var s=0; // If A and B
var l=data.length;
if ($type(ch[6])) { if ($type(ch[6])) {
ch[6]=parseInt(ch[6]); ch[6]=parseInt(ch[6]);
// With A and B // If A and B=0
if (ch[6]==0) { if (ch[6]==0) {
// If B == 0 // If A<0 and B=0
ch[6]=data.length; if (ch[4]<0) {
s=val.length-(-1*ch[4]);
l=val.length;
} }
if (ch[4]>0) { // If A >= 0 and B
// A > 0 else {
s=ch[4];
l=val.length;
}
}
// If A and B > 0
else if (ch[6]>0) {
// If A < 0 and B > 0 or A >= 0 and B > 0
s=ch[4]; s=ch[4];
l=ch[6]; l=ch[6];
} }
// If A and B < 0
else { else {
// A < 0 // If A < 0 and B < 0
s=data.length+ch[4]; if (ch[4]<0) {
if (ch[6]<0) { s=ch[6];
// B < 0 l=false;
l=data.length-s+ch[6]; }
// If A >= 0 and B < 0
else {
s=ch[4]+ch[6];
l=Math.abs(ch[6]);
}
}
}
// If only A
else {
if (ch[4]<0) {
s=ch[4];
l=false;
} }
else { else {
// B > 0
l=ch[6];
}
}
}
else {
// Only A
if (ch[4]>0) {
// A > 0
s=0; s=0;
l=ch[4]; l=ch[4];
} }
}
if (l==false) {
val=val.substr(s);
}
else { else {
// A < 0 val=val.substr(s, Math.abs(l));
s=data.length+ch[4];
l=data.length;
} }
} }
console.log("s = " + s + " / l = " + l);
val=data.substr(s,l); if (ch[7] != undefined) {
}
// Upper or Lower case // Upper or Lower case
if (ch[8]=='!') { if (ch[7].indexOf('!')>=0) {
val=val.toUpperCase(); val=val.toUpperCase();
} }
else if (ch[8]=='_') { else if (ch[7].indexOf('_')>=0) {
val=val.toLowerCase(); val=val.toLowerCase();
} }
// Strip accents // Strip accents
if (ch[9]=='~') { if (ch[7].indexOf('~')>=0) {
val=replaceAccents(val); val=new String(replaceAccents(val));
}
// Escape HTML entities
if (ch[7].indexOf('%')>=0) {
val=val.replace(/[\u00A0-\u9999<>\&]/gim, function(i) {
return '&#'+i.charCodeAt(0)+';';
});
}
} }
return val; return val;
} }
@ -189,18 +217,17 @@ function _getFData_extractAndModify(data,ch) {
* @retval string de-accentuated string * @retval string de-accentuated string
*/ */
function replaceAccents(str) { function replaceAccents(str) {
var new_str = String(str); let accent = "àáâãäçèéêëìíîïñòóôõöùúûüýÿÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ";
var accent = let sans_accent ="aaaaaceeeeiiiinooooouuuuyyAAAAACEEEEIIIINOOOOOUUUUY";
new Array("à","á","â","ã","ä","ç","è","é","ê","ë","ì","í","î","ï","ñ","ò","ó","ô","õ","ö","ù","ú","û","ü","ý","ÿ","À","Á","Â","Ã","Ä","Ç","È","É","Ê","Ë","Ì","Í","Î","Ï","Ñ","Ò","Ó","Ô","Õ","Ö","Ù","Ú","Û","Ü","Ý");
var sans_accent = str = str.split('');
new Array("a","a","a","a","a","c","e","e","e","e","i","i","i","i","n","o","o","o","o","o","u","u","u","u","y","y","A","A","A","A","A","C","E","E","E","E","I","I","I","I","N","O","O","O","O","O","U","U","U","U","Y"); str.forEach((letter, index) => {
if (str && str!= "") { let i = accent.indexOf(letter);
for (i=0; i<accent.length; i++) { if (i != -1) {
var reg_exp= RegExp(accent[i], "gi"); str[index] = sans_accent[i];
new_str = new_str.replace (reg_exp, sans_accent[i]);
} }
} })
return new_str; return str.join('');
} }
/** /**

30
tests/test-getFData.js Normal file
View file

@ -0,0 +1,30 @@
var tests=[
// array(format, test val, test good result)
['%{toto:2}', 'abcdef', 'ab'],
['%{toto:3:-2}', 'abcdef', 'bc'],
['%{toto:1:0}', 'abcdef', 'bcdef'],
['%{toto:-2}', 'abcdef', 'ef'],
['%{toto:-3:2}', 'abcdef', 'de'],
['%{toto:-1}', 'abcdef', 'f'],
['%{toto!}', '<a>tiTé', '<A>TITÉ'],
['%{toto_}', '<a>tiTé', '<a>tité'],
['%{toto~}', '<a>tiTé', '<a>tiTe'],
['%{toto%}', '<a>tiTé', '&#60;a&#62;tiT&#233;'],
['%{toto!%}', '<a>tiTé', '&#60;A&#62;TIT&#201;'],
['%{toto!~}', '<a>tiTé', '<A>TITE'],
['%{toto!~%}', '<a>tiTé', '&#60;A&#62;TITE'],
['%{toto:1!%}', '<a>tiTé', '&#60;'],
['%{toto:1:0!~}', '<a>tiTé', 'A>TITE'],
['%{toto:-3!~%}', '<a>tiTé', 'ITE'],
['%{toto:-3:2!~%}', '<a>tiTé', 'IT'],
];
var nb_tests = tests.length;
for (i = 0; i < nb_tests; i++) {
var result = getFData(tests[i][0], tests[i][1]);
var ok = 'OK';
if (result != tests[i][2]) {
ok = "\n\t!!!! NOK !!!!";
}
console.log('Test ('+i+') : "'+tests[i][0]+'" ('+tests[i][2]+') : "'+tests[i][1]+'" -> "'+result+'" => '+ok);
}

30
tests/test-getFData.php Normal file
View file

@ -0,0 +1,30 @@
<?php
require(realpath(dirname(__FILE__)).'/../public_html/includes/functions.php');
$tests=array(
// array(format, test val, test good result)
array('%{toto:2}', 'abcdef', 'ab'),
array('%{toto:3:-2}', 'abcdef', 'bc'),
array('%{toto:1:0}', 'abcdef', 'bcdef'),
array('%{toto:-2}', 'abcdef', 'ef'),
array('%{toto:-3:2}', 'abcdef', 'de'),
array('%{toto:-1}', 'abcdef', 'f'),
array('%{toto!}', '<a>tiTé', '<A>TITÉ'),
array('%{toto_}', '<a>tiTé', '<a>tité'),
array('%{toto~}', '<a>tiTé', '<a>tiTe'),
array('%{toto%}', '<a>tiTé', '&lt;a&gt;tiT&eacute;'),
array('%{toto!%}', '<a>tiTé', '&lt;A&gt;TIT&Eacute;'),
array('%{toto!~}', '<a>tiTé', '<A>TITE'),
array('%{toto!~%}', '<a>tiTé', '&lt;A&gt;TITE'),
array('%{toto:1!%}', '<a>tiTé', '&lt;'),
array('%{toto:1:0!~}', '<a>tiTé', 'A>TITE'),
array('%{toto:-3!~%}', '<a>tiTé', 'ITE'),
array('%{toto:-3:2!~%}', '<a>tiTé', 'IT'),
);
foreach ($tests as $test) {
$result = getFData($test[0], $test[1]);
$ok = (($result == $test[2])?'OK':"\n\t!!!! NOK !!!!");
echo "Test : \"$test[0]\" ($test[2]) : \"$test[1]\" -> \"$result\" => $ok\n";
}