388 lines
13 KiB
PHP
388 lines
13 KiB
PHP
<?php
|
|
namespace nur\sery;
|
|
|
|
/**
|
|
* Class str: gestion des chaines de caractère "simples"
|
|
*/
|
|
class str {
|
|
/**
|
|
* Retourner $s converti en chaine non nulle, ou "" si $s est fausse (cela
|
|
* n'inclue pas la chaine "0")
|
|
*/
|
|
static final function with($s): string {
|
|
if (!is_string($s)) {
|
|
if (!$s) return "";
|
|
else $s = strval($s);
|
|
}
|
|
return $s;
|
|
}
|
|
|
|
/**
|
|
* Retourner $s converti en chaine non nulle, ou "" si $s est fausse selon les
|
|
* règles de PHP
|
|
*/
|
|
static final function pwith($s): string {
|
|
if (!is_string($s)) {
|
|
if (!$s) return "";
|
|
else $s = strval($s);
|
|
}
|
|
return $s?: "";
|
|
}
|
|
|
|
/**
|
|
* tronquer si nécessaire $s à la valeur $length.
|
|
* la chaine $suffix est rajoutée le cas échéant de façon que la taille
|
|
* totale n'excède pas $length caractères.
|
|
*
|
|
* si $ellips est true et que le troncage est nécessaire, remplacer les 3
|
|
* derniers caractères par "..."
|
|
*/
|
|
static final function trunc(?string $s, int $length, bool $ellips=false, ?string $suffix=null): ?string {
|
|
if ($s === null) return null;
|
|
if ($suffix !== null) $length -= strlen($suffix);
|
|
if (strlen($s) > $length) {
|
|
if ($ellips && $length > 3) $s = substr($s, 0, $length - 3)."...";
|
|
else $s = substr($s, 0, $length);
|
|
}
|
|
if ($suffix !== null) $s .= $suffix;
|
|
return $s;
|
|
}
|
|
|
|
/** trimmer $s */
|
|
static final function trim(?string $s): ?string {
|
|
if ($s === null) return null;
|
|
else return trim($s);
|
|
}
|
|
|
|
/** trimmer $s à gauche */
|
|
static final function ltrim(?string $s): ?string {
|
|
if ($s === null) return null;
|
|
else return ltrim($s);
|
|
}
|
|
|
|
/** trimmer $s à droite */
|
|
static final function rtrim(?string $s): ?string {
|
|
if ($s === null) return null;
|
|
else return rtrim($s);
|
|
}
|
|
|
|
static final function left(?string $s, int $size): ?string {
|
|
if ($s === null) return null;
|
|
else return str_pad($s, $size);
|
|
}
|
|
|
|
static final function right(?string $s, int $size): ?string {
|
|
if ($s === null) return null;
|
|
else return str_pad($s, $size, " ", STR_PAD_LEFT);
|
|
}
|
|
|
|
static final function center(?string $s, int $size): ?string {
|
|
if ($s === null) return null;
|
|
else return str_pad($s, $size, " ", STR_PAD_BOTH);
|
|
}
|
|
|
|
static final function pad0(?string $s, int $size): ?string {
|
|
if ($s === null) return null;
|
|
else return str_pad($s, $size, "0", STR_PAD_LEFT);
|
|
}
|
|
|
|
static final function lower(?string $s): ?string {
|
|
if ($s === null) return null;
|
|
else return strtolower($s);
|
|
}
|
|
|
|
static final function lower1(?string $s): ?string {
|
|
if ($s === null) return null;
|
|
else return lcfirst($s);
|
|
}
|
|
|
|
static final function upper(?string $s): ?string {
|
|
if ($s === null) return null;
|
|
else return strtoupper($s);
|
|
}
|
|
|
|
static final function upper1(?string $s): ?string {
|
|
if ($s === null) return null;
|
|
else return ucfirst($s);
|
|
}
|
|
|
|
static final function upperw(?string $s, ?string $delimiters=null): ?string {
|
|
if ($s === null) return null;
|
|
if ($delimiters !== null) return ucwords($s, $delimiters);
|
|
else return ucwords($s, " _-\t\r\n\f\v");
|
|
}
|
|
|
|
protected static final function _starts_with(string $prefix, string $s, ?int $min_len=null): bool {
|
|
if ($prefix === $s) return true;
|
|
$len = strlen($prefix);
|
|
if ($min_len !== null && ($len < $min_len || $len > strlen($s))) return false;
|
|
return $len == 0 || $prefix === substr($s, 0, $len);
|
|
}
|
|
|
|
/**
|
|
* tester si $s commence par $prefix
|
|
* par exemple:
|
|
* - starts_with("", "whatever") est true
|
|
* - starts_with("fi", "first") est true
|
|
* - starts_with("no", "yes") est false
|
|
*
|
|
* si $min_len n'est pas null, c'est la longueur minimum requise de $prefix
|
|
* pour qu'on teste la correspondance. dans le cas contraire, la valeur de
|
|
* retour est toujours false, sauf s'il y a égalité. e.g
|
|
* - starts_with("a", "abc", 2) est false
|
|
* - starts_with("a", "a", 2) est true
|
|
*/
|
|
static final function starts_with(?string $prefix, ?string $s, ?int $min_len=null): bool {
|
|
if ($s === null || $prefix === null) return false;
|
|
else return self::_starts_with($prefix, $s, $min_len);
|
|
}
|
|
|
|
/** Retourner $s sans le préfixe $prefix s'il existe */
|
|
static final function without_prefix(?string $prefix, ?string $s): ?string {
|
|
if ($s === null || $prefix === null) return $s;
|
|
if (self::_starts_with($prefix, $s)) $s = substr($s, strlen($prefix));
|
|
return $s;
|
|
}
|
|
|
|
/**
|
|
* modifier $s en place pour supprimer le préfixe $prefix s'il existe
|
|
*
|
|
* retourner true si le préfixe a été enlevé.
|
|
*/
|
|
static final function del_prefix(?string &$s, ?string $prefix): bool {
|
|
if ($s === null || !self::_starts_with($prefix, $s)) return false;
|
|
$s = self::without_prefix($prefix, $s);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Retourner $s avec le préfixe $prefix
|
|
*
|
|
* Si $unless_exists, ne pas ajouter le préfixe s'il existe déjà
|
|
*/
|
|
static final function with_prefix(?string $prefix, ?string $s, ?string $sep=null, bool $unless_exists=false): ?string {
|
|
if ($s === null || $prefix === null) return $s;
|
|
if (!self::_starts_with($prefix, $s) || !$unless_exists) $s = $prefix.$sep.$s;
|
|
return $s;
|
|
}
|
|
|
|
/**
|
|
* modifier $s en place pour ajouter le préfixe $prefix
|
|
*
|
|
* retourner true si le préfixe a été ajouté.
|
|
*/
|
|
static final function add_prefix(?string &$s, ?string $prefix, bool $unless_exists=true): bool {
|
|
if (($s === null || self::_starts_with($prefix, $s)) && $unless_exists) return false;
|
|
$s = self::with_prefix($prefix, $s, null, $unless_exists);
|
|
return true;
|
|
}
|
|
|
|
protected static final function _ends_with(string $suffix, string $s, ?int $min_len=null): bool {
|
|
if ($suffix === $s) return true;
|
|
$len = strlen($suffix);
|
|
if ($min_len !== null && ($len < $min_len || $len > strlen($s))) return false;
|
|
return $len == 0 || $suffix === substr($s, -$len);
|
|
}
|
|
|
|
/**
|
|
* tester si $string se termine par $suffix
|
|
* par exemple:
|
|
* - ends_with("", "whatever") est true
|
|
* - ends_with("st", "first") est true
|
|
* - ends_with("no", "yes") est false
|
|
*
|
|
* si $min_len n'est pas null, c'est la longueur minimum requise de $prefix
|
|
* pour qu'on teste la correspondance. dans le cas contraire, la valeur de
|
|
* retour est toujours false, sauf s'il y a égalité. e.g
|
|
* - ends_with("c", "abc", 2) est false
|
|
* - ends_with("c", "c", 2) est true
|
|
*/
|
|
static final function ends_with(?string $suffix, ?string $s, ?int $min_len=null): bool {
|
|
if ($s === null || $suffix === null) return false;
|
|
else return self::_ends_with($suffix, $s, $min_len);
|
|
}
|
|
|
|
/** Retourner $s sans le suffixe $suffix s'il existe */
|
|
static final function without_suffix(?string $suffix, ?string $s): ?string {
|
|
if ($s === null || $suffix === null) return $s;
|
|
if (self::_ends_with($suffix, $s)) $s = substr($s, 0, -strlen($suffix));
|
|
return $s;
|
|
}
|
|
|
|
/**
|
|
* modifier $s en place pour supprimer le suffixe $suffix s'il existe
|
|
*
|
|
* retourner true si le suffixe a été enlevé.
|
|
*/
|
|
static final function del_suffix(?string &$s, ?string $suffix): bool {
|
|
if ($s === null || !self::_ends_with($suffix, $s)) return false;
|
|
$s = self::without_suffix($suffix, $s);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Retourner $s avec le suffixe $suffix
|
|
*
|
|
* Si $unless_exists, ne pas ajouter le suffixe s'il existe déjà
|
|
*/
|
|
static final function with_suffix(?string $suffix, ?string $s, ?string $sep=null, bool $unless_exists=false): ?string {
|
|
if ($s === null || $suffix === null) return $s;
|
|
if (!self::_ends_with($suffix, $s) || !$unless_exists) $s = $s.$sep.$suffix;
|
|
return $s;
|
|
}
|
|
|
|
/**
|
|
* modifier $s en place pour ajouter le suffixe $suffix
|
|
*
|
|
* retourner true si le suffixe a été ajouté.
|
|
*/
|
|
static final function add_suffix(?string &$s, ?string $suffix, bool $unless_exists=true): bool {
|
|
if (($s === null || self::_ends_with($suffix, $s)) && $unless_exists) return false;
|
|
$s = self::with_suffix($suffix, $s, null, $unless_exists);
|
|
return true;
|
|
}
|
|
|
|
/** splitter $s en deux chaines séparées par $sep */
|
|
static final function split_pair(?string $s, string $sep=":"): array {
|
|
if ($s === null) return [null, null];
|
|
$parts = explode($sep, $s, 2);
|
|
if ($parts === false) return [null, null];
|
|
if (count($parts) < 2) $parts[] = null;
|
|
return $parts;
|
|
}
|
|
|
|
/** retourner $line sans son caractère de fin de ligne */
|
|
static final function strip_nl(?string $line): ?string {
|
|
if ($line === null) return null;
|
|
if (substr($line, -2) == "\r\n") {
|
|
$line = substr($line, 0, -2);
|
|
} elseif (substr($line, -1) == "\n") {
|
|
$line = substr($line, 0, -1);
|
|
} elseif (substr($line, -1) == "\r") {
|
|
$line = substr($line, 0, -1);
|
|
}
|
|
return $line;
|
|
}
|
|
|
|
/**
|
|
* normaliser le caractère de fin de ligne: tous les occurrences de [CR]LF et CR sont remplacées par LF
|
|
*/
|
|
static final function norm_nl(?string $s): ?string {
|
|
if ($s === null) return null;
|
|
$s = str_replace("\r\n", "\n", $s);
|
|
$s = str_replace("\r", "\n", $s);
|
|
return $s;
|
|
}
|
|
|
|
/**
|
|
* joindre les éléments de $parts comme avec implode(), mais en ignorant les
|
|
* valeurs fausses (cela n'inclue pas la chaine "0")
|
|
*
|
|
* pour chaque valeur du tableau avec une clé associative, c'est la clé qui
|
|
* est utilisée mais uniquement si la valeur est vraie
|
|
*/
|
|
static final function join(string $glue, ?iterable $values): ?string {
|
|
if ($values === null) return null;
|
|
$pieces = [];
|
|
$index = 0;
|
|
foreach ($values as $key => $value) {
|
|
if (is_array($value)) $value = self::join($glue, $value);
|
|
if ($key === $index) {
|
|
$index++;
|
|
if (cv::t($value)) $pieces[] = $value;
|
|
} elseif (cv::t($value)) {
|
|
$pieces[] = $key;
|
|
}
|
|
}
|
|
return implode($glue, $pieces);
|
|
}
|
|
|
|
/**
|
|
* comme {@link join()} mais en ignorant les valeurs fausses selon les règles
|
|
* de PHP
|
|
*/
|
|
static final function pjoin(string $glue, ?iterable $values): ?string {
|
|
if ($values === null) return null;
|
|
$pieces = [];
|
|
$index = 0;
|
|
foreach ($values as $key => $value) {
|
|
if (is_array($value)) $value = self::join($glue, $value);
|
|
if ($key === $index) {
|
|
$index++;
|
|
if ($value) $pieces[] = $value;
|
|
} elseif ($value) {
|
|
$pieces[] = $key;
|
|
}
|
|
}
|
|
return implode($glue, $pieces);
|
|
}
|
|
|
|
const CAMEL_PATTERN0 = '/([A-Z0-9]+)$/A';
|
|
const CAMEL_PATTERN1 = '/([A-Z0-9]+)[A-Z]/A';
|
|
const CAMEL_PATTERN2 = '/([^A-Z]+)/A';
|
|
const CAMEL_PATTERN3 = '/([A-Z][^A-Z]*)/A';
|
|
|
|
/**
|
|
* convertir une chaine de la forme "camelCase" en "under_score". le premier
|
|
* ensemble de caractères en majuscule est considéré comme étant en minuscule
|
|
*
|
|
* par exemple:
|
|
* - 'myCamelCase' devient 'my_camel_case'
|
|
* - 'AValue' devient 'a_value'
|
|
* - 'UPPERValue' devient 'upper_value'
|
|
* - 'UPPER' devient 'upper'
|
|
* - 'aXYZ' devient 'a_x_y_z'
|
|
*
|
|
* $delimiter est le séparateur en sortie ('_' par défaut)
|
|
* $upper indique s'il faut transformer le résultat en majuscule
|
|
*/
|
|
static final function camel2us(?string $camel, bool $upper=false, string $delimiter="_"): ?string {
|
|
if ($camel === null || $camel === "") return $camel;
|
|
$parts = [];
|
|
if (preg_match(self::CAMEL_PATTERN0, $camel, $vs, PREG_OFFSET_CAPTURE)) {
|
|
# que des majuscules
|
|
} elseif (preg_match(self::CAMEL_PATTERN1, $camel, $vs, PREG_OFFSET_CAPTURE)) {
|
|
# préfixe en majuscule
|
|
} elseif (preg_match(self::CAMEL_PATTERN2, $camel, $vs, PREG_OFFSET_CAPTURE)) {
|
|
# préfixe en minuscule
|
|
} else {
|
|
throw ValueException::invalid_kind($camel, "camel string");
|
|
}
|
|
$parts[] = strtolower($vs[1][0]);
|
|
$index = intval($vs[1][1]) + strlen($vs[1][0]);
|
|
while (preg_match(self::CAMEL_PATTERN3, $camel, $vs, PREG_OFFSET_CAPTURE, $index)) {
|
|
$parts[] = strtolower($vs[1][0]);
|
|
$index = intval($vs[1][1]) + strlen($vs[1][0]);
|
|
}
|
|
$us = implode($delimiter, $parts);
|
|
if ($upper) $us = strtoupper($us);
|
|
return $us;
|
|
}
|
|
|
|
const US_PATTERN = '/([ _\-\t\r\n\f\v])/';
|
|
|
|
/**
|
|
* convertir une chaine de la forme "under_score" en "camelCase"
|
|
*
|
|
* par exemple, 'my_camel_case' devient 'myCamelCalse'
|
|
* et 'UPPER_VALUE' devient 'upperValue'
|
|
*
|
|
* si la chaine de départ ne contient pas de delimiter, e.g 'myValue', elle
|
|
* est retournée inchangée
|
|
*/
|
|
static final function us2camel(?string $us, ?string $delimiters=null): ?string {
|
|
if ($us === null || $us === "") return $us;
|
|
if ($delimiters === null) $pattern = self::US_PATTERN;
|
|
else $pattern = '/(['.preg_quote($delimiters).'])/';
|
|
$parts = preg_split($pattern, $us);
|
|
$count = count($parts);
|
|
if ($count == 1) return $us;
|
|
for ($i = 0; $i < $count; $i++) {
|
|
$part = strtolower($parts[$i]);
|
|
if ($i > 0) $part = ucfirst($part);
|
|
$parts[$i] = $part;
|
|
}
|
|
return implode("", $parts);
|
|
}
|
|
}
|