List Converter — C++ 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 C++ implementation — the same logic the interactive tool runs, in a shareable, citable form.
// List Converter — split/trim/dedup/sort/join between separators — C++ (C++20) port of the list-converter tool.
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
#include <unordered_set>
#include <vector>
namespace list_converter {
// Resolve a TS-style separator name to its glue; unknown names pass through
// as a literal separator (the TS resolveSep behavior).
inline std::string resolve_sep(const std::string& name) {
if (name == "newline") return "\n";
if (name == "comma") return ",";
if (name == "space") return " ";
if (name == "pipe") return "|";
if (name == "semicolon") return ";";
if (name == "tab") return "\t";
return name;
}
struct Options { // defaults match the TS ListOptions (newline -> comma)
std::string from = "newline", to = "comma";
bool trim = false, remove_empty = false, unique = false;
bool sort = false, case_insensitive = false;
};
inline std::vector<std::string> split(const std::string& s, const std::string& sep) {
std::vector<std::string> out;
if (sep.empty()) { out.push_back(s); return out; }
size_t start = 0;
while (true) { // mirrors Go strings.Split: trailing empties survive
size_t hit = s.find(sep, start);
if (hit == std::string::npos) { out.push_back(s.substr(start)); return out; }
out.push_back(s.substr(start, hit - start));
start = hit + sep.size();
}
}
inline std::string lower(std::string s) {
std::transform(s.begin(), s.end(), s.begin(),
[](unsigned char c) { return std::tolower(c); });
return s;
}
// Convert a list between separators: split -> (trim) -> (drop empties) ->
// (dedup, first occurrence wins) -> (stable sort) -> join. Mirrors the Go twin.
inline std::string convert(const std::string& input, const Options& o = {}) {
std::vector<std::string> items = split(input, resolve_sep(o.from));
const std::string to = resolve_sep(o.to);
if (o.trim)
for (auto& s : items) {
const auto b = s.find_first_not_of(" \t\r\n");
if (b == std::string::npos) { s.clear(); continue; }
s.erase(s.find_last_not_of(" \t\r\n") + 1).erase(0, b);
}
if (o.remove_empty) items.erase(std::remove_if(items.begin(), items.end(),
[](const std::string& s) { return s.empty(); }),
items.end());
if (o.unique) { // the set holds keys only; items keep their casing
std::unordered_set<std::string> seen;
items.erase(std::remove_if(items.begin(), items.end(),
[&](const std::string& s) {
return !seen.insert(o.case_insensitive ? lower(s) : s).second;
}),
items.end());
}
if (o.sort) // std::stable_sort: equal keys keep their input order
std::stable_sort(items.begin(), items.end(),
[&](const std::string& a, const std::string& b) {
return o.case_insensitive ? lower(a) < lower(b) : a < b;
});
std::string out;
for (size_t i = 0; i < items.size(); i++) {
if (i != 0) out += to;
out += items[i];
}
return out;
}
} // namespace list_converter
int main() {
using namespace list_converter;
Options o;
o.trim = o.remove_empty = o.unique = o.sort = o.case_insensitive = true;
std::cout << convert("b\n a \nB\na\n\nc", o) << "\n"; // a,b,c
}
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 →