When padding a string for display in a CLI script, I’ve found that escape sequences seem to confuse the mb_str_pad() function.
Specifically, say I want a list of results for the word time: pretend the results are:
Now is the time for all good men Record A
What time is the party? Record B
The bus was actually on time yesterday Record C
I’d like to display results in a list with padded columns, highlighting the match with color, something like
Now is the **YLW** time **WHT** for all good men
What **YLW** time **WHT** is the party?
The bus was actually on **YLW** time **WHT** yesterday
where YLW and WHT are the escape sequences for yellow and white foregrounds respectively. The padding works fine when I omit the escape sequences, but the columns are truncated when they are included:
Now is the time for all good men Record A
What time is the party? Record B
The bus was actually on time yesterday Record C
To confuse matters, a var_dump() says the strings are the expected length (120). But copy/paste them from the terminal to mousepad or some such and they aren’t; they’re 100.
Here are two solutions. See what this does for you. See if this helps you answer your own questions. If you get stuck, I will explain.
<?php
// OPTION ONE
// 1. Pad the plain text to the desired width
$plain = "Now is the time for all good men";
$padded = mb_str_pad($plain, 50);
// 2. Now replace "time" with the colored version (length doesn't change visually)
$highlighted = str_replace('time', "\033[33mtime\033[37m", $padded);
echo $highlighted . "Record A\n";
// OPTION TWO
function mb_str_pad_ansi(string $input, int $pad_length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT): string
{
// 1. Remove all ANSI escape sequences to get the "visible" text
$strip_ansi = preg_replace('/\033\[[0-9;]*m/', '', $input);
// 2. Get the visible length (multibyte-safe)
$visible_len = mb_strlen($strip_ansi);
// 3. Calculate how many padding characters are actually needed
$needed_padding = $pad_length - $visible_len;
if ($needed_padding <= 0) {
return $input;
}
// 4. Apply padding ONLY to the visible length by repeating the pad string
return $input . str_repeat($pad_string, $needed_padding);
}
// Usage:
$highlighted = "\033[33mtime\033[37m"; // Your yellow/white example
$line = "Now is the " . $highlighted . " for all good men";
echo mb_str_pad_ansi($line, 50) . "Record A\n";