Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to erase non-alpha chars and lowercase the alpha chars in a single pass of a string?

Given a string:

std::string str{"This i_s A stRIng"};

Is it possible to transform it to lowercase and remove all non-alpha characters in a single pass?

Expected result:

this is a string

I know you can use std::transform(..., ::tolower) and string.erase(remove_if()) combination to make two passes, or it can be done manually by iterating each character, but is there a way to do something that would combine the std::transform and erase calls without having to run through the string multiple times?

like image 636
cbrng Avatar asked Nov 18 '25 05:11

cbrng


2 Answers

C++20 ranges allow algorithms to be combined, in a one-pass fashion.

std::string str{"This i_s A stRIng"};
std::string out;

auto is_alpha_or_space = [](unsigned char c){ return isalpha(c) || isspace(c); };
auto safe_tolower = [](unsigned char c){ return tolower(c); };

std::ranges::copy( str
    | std::views::filter(is_alpha_or_space)
    | std::views::transform(safe_tolower)
    , std::back_inserter(out));

See it on Compiler Explorer

like image 68
Drew Dormann Avatar answered Nov 19 '25 19:11

Drew Dormann


First let me notice that you seem to want to filter alphabetic characters or spaces, that is, characters l for which std::isalpha(l) || std::isspace(l) returns true.

Assuming this, you can achieve what you want using std::accumulate

str = std::accumulate(str.begin(), str.end(), std::string{},
    [](const std::string& s, const auto& l) {
        if (std::isalpha(l, std::locale()) || std::isspace(l, std::locale()))
             return s + std::tolower(l, std::locale());
        else
             return s;
    });

See it Live on Coliru.

like image 25
francesco Avatar answered Nov 19 '25 20:11

francesco