The text a page shows is often made in its PHP first: a title cut to fit a card, a column name turned into a label, a slug for a database column, a token for a mail. PHP's own substr and ucwords count bytes and know only ASCII; the padStr functions count characters, so an accented letter or an emoji is never cut in half. They are plain functions, loaded on every request like the rest of pad/lib/.

functionwhat it answers
padStrLimit ( $text, $limit = 100, $end = '...' )at most $limit characters, $end added when something was cut
padStrWords ( $text, $words = 100, $end = '...' )at most $words words
padStrExcerpt ( $text, $phrase, $radius = 100, $omission = '...' )the phrase with $radius characters on either side, found case-insensitively
padStrSquish ( $text )trimmed, every run of whitespace one space
padStrCamel, padStrStudly, padStrSnake ( $text, $delimiter = '_' ), padStrKebab, padStrHeadlineuserName, UserName, user_name, user-name, User Name - from a name in any of those cases
padStrTitle ( $text )every word with a capital
padStrSlug ( $text, $separator = '-' )a readable URL part - what the slug pipe gives
padStrAfter, padStrAfterLast, padStrBefore, padStrBeforeLast ( $text, $search )the text after or before the first or last occurrence - what the pipes of those names give
padStrBetween ( $text, $from, $to )what stands between the first $from and the last $to
padStrIs ( $pattern, $value )whether the value matches a pattern with * wildcards, or one of a list
padStrMask ( $text, $character, $index, $length = NULL )a stretch of the text replaced by one character
padStrPlural ( $word, $count = 2 ), padStrSingular ( $word )the English plural or singular of a word
padStrRandom ( $length = 16 )random letters and digits
padStrUuid ( $version = 4 )a version 4 (random) or version 7 (time-ordered) UUID

Shortening text

padStrLimit cuts at a number of characters and padStrWords at a number of words; both trim the space the cut leaves, add $end only when something was cut, and give a text that fits back as it is. padStrExcerpt is the snippet of a search result: the place the phrase stands, with the text around it. padStrSquish makes text pasted into a form field compare and store the same way, tabs, newlines and no-break spaces included.

PHP
fragments/strings_1.php
HTML
fragments/strings_1.pad
Result
<?php

$text
= 'PAD templates drive the flow: data, logic and output '
. 'all follow the template.';

$limit = padStrLimit ( $text, 20 );
$words = padStrWords ( $text, 4 );
$excerpt = padStrExcerpt ( $text, 'LOGIC', 10 );
$squish = padStrSquish ( " data,\n\t logic and output " );

?>
<p>{$limit}</p>
<p>{$words}</p>
<p>{$excerpt}</p>
<p>[{$squish}]</p>

PAD templates drive...

PAD templates drive the...

...ow: data, logic and outpu...

[data, logic and output]

Names in every case

The case functions read the words of a name whatever case it is in - an underscore, a dash, a space or a change of case separates them - and write them in the case asked for, so created_at, createdAt and CreatedAt all turn into each other. padStrHeadline makes a label of a column name; padStrTitle recases a sentence and leaves the rest of it as it is.

PHP
fragments/strings_2.php
HTML
fragments/strings_2.pad
Result
<?php

$names
= [ 'created_at', 'orderTotal',
'customer-name', 'HTMLParser' ];

$columns = [];

foreach (
$names as $column )
$columns [] = [
'column' => $column,
'camel' => padStrCamel ( $column ),
'studly' => padStrStudly ( $column ),
'snake' => padStrSnake ( $column ),
'kebab' => padStrKebab ( $column ),
'headline' => padStrHeadline ( $column )
];

$sentence = padStrTitle ( 'the quick brown fox' );

?>
<table>
<tr><th>name</th><th>camel</th>
<th>studly</th><th>snake</th>
<th>kebab</th><th>headline</th></tr>
{columns}
<tr><td>{$column}</td><td>{$camel}</td>
<td>{$studly}</td><td>{$snake}</td>
<td>{$kebab}</td><td>{$headline}</td></tr>
{/columns}
</table>
<p>{$sentence}</p>
namecamel studlysnake kebabheadline
created_atcreatedAt CreatedAtcreated_at created-atCreated At
orderTotalorderTotal OrderTotalorder_total order-totalOrder Total
customer-namecustomerName CustomerNamecustomer_name customer-nameCustomer Name
HTMLParserhtmlParser HtmlParserhtml_parser html-parserHtml Parser

The Quick Brown Fox

Slugs and cutting at a marker

padStrSlug is the slug pipe - the pipe calls it - so a slug stored when a post is saved is the slug a template makes for its link. The same holds for after, afterLast, before and beforeLast: a text without the search string comes back unchanged. padStrBetween takes what follows the first $from up to the last $to.

PHP
fragments/strings_3.php
HTML
fragments/strings_3.pad
Result
<?php

$post
= 'Crème Brûlée & Co. - a recipe';
$slug = padStrSlug ( $post );

$file = 'shop/orders/list.pad';
$top = padStrBefore ( $file, '/' );
$folder = padStrBeforeLast ( $file, '/' );
$base = padStrAfterLast ( $file, '/' );

$html = '<title>Orders</title>';
$heading = padStrBetween ( $html, '<title>', '</title>' );

?>
<p>{$slug} - the pipe: {$post | slug}</p>
<p>{$top} | {$folder} | {$base}</p>
<p>{$heading}</p>

creme-brulee-co-a-recipe - the pipe: creme-brulee-co-a-recipe

shop | shop/orders | list.pad

Orders

Patterns and masks

padStrIs matches a value against a pattern in which * stands for any run of characters - a list of patterns matches when one of them does - without writing a regular expression. padStrMask hides part of a text: a negative index counts from the end, a negative length stops that many characters before it.

PHP
fragments/strings_4.php
HTML
fragments/strings_4.pad
Result
<?php

$allowed
= [ 'admin/*', 'reports/*.pdf' ];

$paths = [ 'admin/users',
'reports/may.pdf',
'reports/may.csv' ];

$checks = [];

foreach (
$paths as $path )
$checks [] = [
'path' => $path,
'allowed' => padStrIs ( $allowed, $path ) ? 'yes' : 'no'
];

$card = padStrMask ( '4111 1111 1111 1234', '*', 0, -4 );
$email = padStrMask ( 'ann.smith@example.com', '*', 1, 8 );

?>
{checks}
<p>{$path}: {$allowed}</p>
{/checks}
<p>{$card}</p>
<p>{$email}</p>

admin/users: yes

reports/may.pdf: yes

reports/may.csv: no

***************1234

a********@example.com

Plural and singular

padStrPlural gives the English plural of the last word of a text: the irregular words (person, child, mouse, knife ...), the uncountable ones (sheep, information, equipment ...) and the rules for -y, -s, -x, -ch and the rest. A count of one keeps the word, so "$n " . padStrPlural ( 'file', $n ) reads right for every number; an array or a Countable counts as its size. The case of the word is kept: Person, People; PERSON, PEOPLE. padStrSingular goes the other way.

PHP
fragments/strings_5.php
HTML
fragments/strings_5.pad
Result
<?php

$carts
= [];

foreach ( [
0, 1, 2 ] as $n )
$carts [] = [
'n' => $n,
'items' => padStrPlural ( 'item', $n ),
'people' => padStrPlural ( 'person', $n )
];

$nouns = [ 'city', 'child', 'knife', 'analysis',
'sheep', 'Person', 'blogPost' ];

$words = [];

foreach (
$nouns as $word )
$words [] = [
'word' => $word,
'plural' => padStrPlural ( $word ),
'back' => padStrSingular ( padStrPlural ( $word ) )
];

?>
{carts}
<p>{$n} {$items} for {$n} {$people}</p>
{/carts}
<table>
<tr><th>word</th><th>plural</th><th>singular again</th></tr>
{words}
<tr><td>{$word}</td><td>{$plural}</td><td>{$back}</td></tr>
{/words}
</table>

0 items for 0 people

1 item for 1 person

2 items for 2 people

wordpluralsingular again
citycitiescity
childchildrenchild
knifeknivesknife
analysisanalysesanalysis
sheepsheepsheep
PersonPeoplePerson
blogPostblogPostsblogPost

Random strings and UUIDs

padStrRandom draws letters and digits with random_int, PHP's secure generator - good for a token or a code to mail. padStrUuid makes a UUID as RFC 9562 writes it: version 4 is random; version 7 starts with the time, so ids made later sort later and a database index on them stays in order. The example shows their shape, as their value differs on every request.

PHP
fragments/strings_6.php
HTML
fragments/strings_6.pad
Result
<?php

$token
= padStrRandom ( 32 );
$first = padStrUuid ( 7 );
$later = padStrUuid ( 7 );
$id = padStrUuid ();

// Random on every request: what is shown is their shape,
// not their value.

$tokenShape = preg_match ( '/^[A-Za-z0-9]{32}$/', $token )
?
'32 letters and digits' : 'wrong';
$shape = preg_replace ( '/[0-9a-f]/', 'x', $id );
$versions = $id [14] . ' and ' . $first [14];
$ordered = strcmp ( $later, $first ) > 0 ? 'yes' : 'no';

?>
<p>token: {$tokenShape}</p>
<p>uuid: {$shape}, versions {$versions}</p>
<p>a later version 7 sorts after an earlier one: {$ordered}</p>

token: 32 letters and digits

uuid: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, versions 4 and 7

a later version 7 sorts after an earlier one: yes

Wrong input

NULL and FALSE are read as an empty text and a number as its digits, so the functions take a database value as it comes. An array, a negative limit, an unknown UUID version or an empty mask character is a mistake of the author: it is reported as a PAD error naming the function, and the function answers an empty value.