List Converter — PHP source
Transform a list between separators (newline, comma, space, pipe, semicolon, tab) with trim, dedupe, sort, and empty-removal options. Runs entirely in your browser, with a shareable link.
This is the PHP implementation — the same logic the interactive tool runs, in a shareable, citable form.
<?php
/**
* list-converter — convert lists between separators (newline/comma/space/pipe/...).
*
* Language: PHP (8.1+, standard library only — mbstring used for safe
* multibyte handling, which is effectively universal in modern PHP)
* Source: CosmoDev polyglot showcase port of the List Converter tool, ported
* from cli/list-converter/list-converter.go (the Go CLI twin), which
* is itself the lock-step mirror of src/lib/list-converter.ts (the
* canonical TypeScript implementation).
* License: display source — part of CosmoDev's polyglot tool pages.
*
* Design goals:
* - Pure + deterministic; never throws.
* - Functionally equivalent to the Go twin: same inputs -> same outputs.
* - Self-contained: stdlib only (no Composer packages).
*
* Pipeline: split on the "from" separator -> (trim each item) -> (drop empties)
* -> (dedup, optionally case-insensitive, first occurrence wins) -> (stable
* sort, optionally case-insensitive) -> join with the "to" separator. The
* Separator enum and options mirror the Go types exactly; defaults are
* from=newline, to=comma (the TS resolveSep fallbacks).
*/
declare(strict_types=1);
namespace CosmoDev\ListConverter;
/**
* A built-in list separator. Mirrors the Go twin's Separator enum; the default
* NEWLINE matches the TS "from" default. Backed by the literal separator
* string so it doubles as the split/join glue (PHP enums can't be zero-valued
* integers with a meaningful char, so a string-backed enum is the clean fit).
*/
enum Separator: string
{
case Newline = "\n";
case Comma = ',';
case Space = ' ';
case Pipe = '|';
case Semicolon = ';';
case Tab = "\t";
/**
* Resolve by the TS-style lowercase name ("comma", "newline", ...).
* Provided for API symmetry with the TS source; callers normally pass the
* enum case directly.
*/
public static function fromName(string $name): self
{
return match ($name) {
'newline' => self::Newline,
'comma' => self::Comma,
'space' => self::Space,
'pipe' => self::Pipe,
'semicolon' => self::Semicolon,
'tab' => self::Tab,
default => self::from($name),
};
}
}
/**
* Options for convert(). Each key is optional; defaults match the Go twin.
*
* - from: Separator default Newline source separator
* - to: Separator default Comma target separator
* - trim: bool default false trim each split item
* - removeEmpty: bool default false drop items equal to ''
* - unique: bool default false keep first occurrence only
* - sort: bool default false stable-sort ascending
* - caseInsensitive: bool default false lowercase keys for unique/sort
*/
function listconverter_default_options(): array
{
return [
'from' => Separator::Newline,
'to' => Separator::Comma,
'trim' => false,
'removeEmpty' => false,
'unique' => false,
'sort' => false,
'caseInsensitive' => false,
];
}
/**
* Lowercase a string with the same observable effect as Go's strings.ToLower
* for the ASCII range this tool targets. mb_strtolower handles multibyte input
* safely.
*/
function listconverter_lower(string $s): string
{
return mb_strtolower($s, 'UTF-8');
}
/**
* Convert a list between separators. Never throws; an empty $input simply
* yields a one-item list joined back together (mirroring Go's
* strings.Split("", sep) == [""]).
*/
function listconvert(string $input, array $options = []): string
{
$options = array_merge(listconverter_default_options(), $options);
$from = $options['from'] instanceof Separator ? $options['from']->value : (string) $options['from'];
$to = $options['to'] instanceof Separator ? $options['to']->value : (string) $options['to'];
$items = explode($from, $input);
if (!empty($options['trim'])) {
$items = array_map('trim', $items);
}
if (!empty($options['removeEmpty'])) {
$items = array_values(array_filter($items, fn ($s) => $s !== ''));
}
if (!empty($options['unique'])) {
// Keyed by the (optionally lowercased) value; the first-seen item
// survives with its original casing. PHP preserves insertion order
// across array keys, so one pass dedups and keeps order.
$seen = [];
foreach ($items as $s) {
$key = !empty($options['caseInsensitive']) ? listconverter_lower($s) : $s;
if (!array_key_exists($key, $seen)) {
$seen[$key] = $s;
}
}
$items = array_values($seen);
}
if (!empty($options['sort'])) {
// PHP's sort isn't stable across all versions, but usort has been
// stable since 8.0. We lowercase only for comparison when
// caseInsensitive is set, leaving the stored values untouched.
$ci = !empty($options['caseInsensitive']);
usort($items, function (string $a, string $b) use ($ci): int {
$ka = $ci ? listconverter_lower($a) : $a;
$kb = $ci ? listconverter_lower($b) : $b;
return $ka <=> $kb;
});
}
return implode($to, $items);
}
/**
* Convenience wrapper using default options — the common "newline list to a
* comma list" case (matches the tool's default From/To).
*/
function listconvert_default(string $input): string
{
return listconvert($input, listconverter_default_options());
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →