Copy docker run --rm zchencow/innozverse-php:latest php -r '
<?php
// ── Named capture groups ──────────────────────────────────────────────────────
echo "=== Named Capture Groups ===" . PHP_EOL;
$orderLog = [
"2026-01-15 09:23:41 ORDER #1001 Surface Pro qty=2 total=$1728.00 region=West status=shipped",
"2026-02-03 14:05:22 ORDER #1002 Surface Pen qty=5 total=$249.95 region=East status=pending",
"2026-02-18 16:44:00 ORDER #1003 Office 365 qty=1 total=$99.99 region=North status=delivered",
"2026-03-01 11:30:15 ORDER #9999 USB-C Hub qty=10 total=$299.90 region=South status=cancelled",
];
// Named groups make the regex self-documenting
$pattern = '/^(?P<date>\d{4}-\d{2}-\d{2}) (?P<time>\d{2}:\d{2}:\d{2}) ORDER #(?P<id>\d+) (?P<product>.+?) qty=(?P<qty>\d+) total=\$(?P<total>[\d.]+)\s+region=(?P<region>\w+) status=(?P<status>\w+)$/';
$orders = [];
foreach ($orderLog as $line) {
if (preg_match($pattern, $line, $m)) {
$orders[] = [
"date" => $m["date"],
"id" => (int) $m["id"],
"product" => trim($m["product"]),
"qty" => (int) $m["qty"],
"total" => (float) $m["total"],
"region" => $m["region"],
"status" => $m["status"],
];
}
}
foreach ($orders as $o) {
printf(" #%-4d %-15s ×%d \$%-8.2f %-8s %s%s",
$o["id"], $o["product"], $o["qty"], $o["total"], $o["region"], $o["status"], PHP_EOL);
}
$totalRevenue = array_sum(array_column($orders, "total"));
printf(" Total revenue: \$%.2f%s", $totalRevenue, PHP_EOL);
// ── Lookahead and lookbehind ──────────────────────────────────────────────────
echo PHP_EOL . "=== Lookahead & Lookbehind ===" . PHP_EOL;
$prices = ["$864.00", "€299.99", "£49.99", "¥12000", "$1299.00", "$0.00"];
// Positive lookahead: digits followed by .00 (end of cents)
$wholeDollar = array_filter($prices, fn($p) => preg_match('/\d+(?=\.00)/', $p));
echo "Whole dollar amounts: " . implode(", ", $wholeDollar) . PHP_EOL;
// Negative lookahead: $ prices that are NOT $0.00
$nonZero = array_filter($prices, fn($p) => preg_match('/^\$(?!0\.00)[\d.]+$/', $p));
echo "Non-zero USD: " . implode(", ", $nonZero) . PHP_EOL;
// Positive lookbehind: numbers preceded by $
$usdAmounts = [];
foreach ($prices as $p) {
if (preg_match('/(?<=\$)[\d.]+/', $p, $m)) $usdAmounts[] = (float)$m[0];
}
echo "USD amounts: " . implode(", ", $usdAmounts) . PHP_EOL;
// ── preg_replace_callback ─────────────────────────────────────────────────────
echo PHP_EOL . "=== preg_replace_callback ===" . PHP_EOL;
// Convert markdown-ish product links to HTML
$text = "Buy the [[Surface Pro|/products/1]] for \$864 or the [[Surface Pen|/products/2]] for \$49.99.";
$html = preg_replace_callback(
'/\[\[(?P<label>[^\|]+)\|(?P<url>[^\]]+)\]\]/',
fn($m) => "<a href=\"{$m["url"]}\">{$m["label"]}</a>",
$text
);
echo " Input: " . $text . PHP_EOL;
echo " Output: " . $html . PHP_EOL;
// Mask credit card numbers: keep last 4
$payment = "Charged card 4111-1111-1111-1234 and backup 5500-0000-0000-0004";
$masked = preg_replace_callback(
'/(\d{4})-(\d{4})-(\d{4})-(\d{4})/',
fn($m) => "****-****-****-{$m[4]}",
$payment
);
echo PHP_EOL . " Original: " . $payment . PHP_EOL;
echo " Masked: " . $masked . PHP_EOL;
// Capitalise first letter of each word in product names (title-case)
$names = ["surface pro 12 inch", "usb-c hub v2", "office 365 family"];
foreach ($names as $name) {
$titleCase = preg_replace_callback(
'/\b([a-z])/',
fn($m) => strtoupper($m[1]),
$name
);
echo " " . str_pad($name, 25) . " -> " . $titleCase . PHP_EOL;
}
'