Sök…


Introduktion

Regular Expressions (ibland kallad regexs eller regexps) är en textsyntax som representerar mönstren som kan matchas i de strängar som används.

Regelbundna uttryck, introducerade i c ++ 11 , kan valfritt stödja en returresa av matchade strängar eller en annan textsyntax som definierar hur man ersätter matchade mönster i strängar som används.

Syntax

  • regex_match // Returnerar om hela karaktärsekvensen matchades av regexen, valfritt fånga in i ett matchningsobjekt
  • regex_search // Returnerar om en del av karaktärsekvensen matchades av regexen, valfritt fångas in i ett matchningsobjekt
  • regex_replace // Returnerar inmatningsteckensekvensen ändrad av en regex via en ersättningsformatssträng
  • regex_token_iterator // Initierad med en teckensekvens definierad av iteratorer, en lista med fångstindex att iterera över och en regex. Dereferencing returnerar den för närvarande indexerade matchen för regex. Inkrementering flyttar till nästa fångstindex eller om för närvarande vid sista index, återställer indexet och hindrar nästa förekomst av en regexmatch i teckensekvensen
  • regex_iterator // Initierad med en karaktersekvens definierad av iteratorer och en regex. Dereferencing returnerar den del av karaktersekvensen som hela regexet för närvarande matchar. Inkrementering hittar nästa förekomst av en regex-matchning i teckensekvensen

parametrar

Signatur Beskrivning
bool regex_match(BidirectionalIterator first, BidirectionalIterator last, smatch& sm, const regex& re, regex_constraints::match_flag_type flags) BidirectionalIterator är vilken karaktär iterator som tillhandahåller inkrement och minskning operatörers smatch kan vara cmatch eller någon annan variant av match_results som accepterar typen av BidirectionalIterator kan smatch argumentet utelämnas om resultaten från regexen inte behövs Returnerar om re matchar hela tecknet sekvens definierad av first och last
bool regex_match(const string& str, smatch& sm, const regex re&, regex_constraints::match_flag_type flags) string kan vara antingen en const char* eller en L-Value- string , funktionerna som accepterar en R-Value- string raderas uttryckligen smatch kan vara cmatch eller någon annan variant av match_results som accepterar typen av str argumentet för smatch kan utelämnas om resultaten från regexen behövs inte Returnerar om re matchar hela teckensekvensen definierad av str
const auto input = "Some people, when confronted with a problem, think \"I know, I'll use regular expressions.\""s;
smatch sm;

cout << input << endl;

// If input ends in a quotation that contains a word that begins with "reg" and another word begining with "ex" then capture the preceeding portion of input
if (regex_match(input, sm, regex("(.*)\".*\\breg.*\\bex.*\"\\s*$"))) {
    const auto capture = sm[1].str();
    
    cout << '\t' << capture << endl; // Outputs: "\tSome people, when confronted with a problem, think\n"
    
    // Search our capture for "a problem" or "# problems"
    if(regex_search(capture, sm, regex("(a|d+)\\s+problems?"))) {
        const auto count = sm[1] == "a"s ? 1 : stoi(sm[1]);
        
        cout << '\t' << count << (count > 1 ? " problems\n" : " problem\n"); // Outputs: "\t1 problem\n"
        cout << "Now they have " << count + 1 << " problems.\n"; // Ouputs: "Now they have 2 problems\n"
    }
}

Levande exempel

regex_replace Exempel

Den här koden tar olika typer av stag och konverterar dem till One True Brace Style :

const auto input = "if (KnR)\n\tfoo();\nif (spaces) {\n    foo();\n}\nif (allman)\n{\n\tfoo();\n}\nif (horstmann)\n{\tfoo();\n}\nif (pico)\n{\tfoo(); }\nif (whitesmiths)\n\t{\n\tfoo();\n\t}\n"s;

cout << input << regex_replace(input, regex("(.+?)\\s*\\{?\\s*(.+?;)\\s*\\}?\\s*"), "$1 {\n\t$2\n}\n") << endl;

Levande exempel

regex_token_iterator Exempel

En std::regex_token_iterator tillhandahåller ett fantastiskt verktyg för att extrahera element i en kommaseparerad värdefil . Bortsett från fördelarna med iteration kan denna iterator också fånga undkommade komma där andra metoder kämpar:

const auto input = "please split,this,csv, ,line,\\,\n"s;
const regex re{ "((?:[^\\\\,]|\\\\.)+)(?:,|$)" };
const vector<string> m_vecFields{ sregex_token_iterator(cbegin(input), cend(input), re, 1), sregex_token_iterator() };

cout << input << endl;

copy(cbegin(m_vecFields), cend(m_vecFields), ostream_iterator<string>(cout, "\n"));

Levande exempel

En anmärkningsvärd gotcha med regex-iteratorer är att regex argumentet måste vara ett L-värde. Ett R-värde fungerar inte .

regex_iterator Exempel

När bearbetning av inspelningar måste göras iterativt är en regex_iterator ett bra val. Genomförande av en regex_iterator returnerar ett match_result . Det här är bra för villkorade fångar eller fångar som är beroende av varandra. Låt oss säga att vi vill symbolisera någon C ++ -kod. Given:

enum TOKENS {
    NUMBER,
    ADDITION,
    SUBTRACTION,
    MULTIPLICATION,
    DIVISION,
    EQUALITY,
    OPEN_PARENTHESIS,
    CLOSE_PARENTHESIS
};

Vi kan tokenisera den här strängen: const auto input = "42/2 + -8\t=\n(2 + 2) * 2 * 2 -3"s med en regex_iterator som denna:

vector<TOKENS> tokens;
const regex re{ "\\s*(\\(?)\\s*(-?\\s*\\d+)\\s*(\\)?)\\s*(?:(\\+)|(-)|(\\*)|(/)|(=))" };

for_each(sregex_iterator(cbegin(input), cend(input), re), sregex_iterator(), [&](const auto& i) {
    if(i[1].length() > 0) {
        tokens.push_back(OPEN_PARENTHESIS);
    }
    
    tokens.push_back(i[2].str().front() == '-' ? NEGATIVE_NUMBER : NON_NEGATIVE_NUMBER);
    
    if(i[3].length() > 0) {
        tokens.push_back(CLOSE_PARENTHESIS);
    }        
    
    auto it = next(cbegin(i), 4);
    
    for(int result = ADDITION; it != cend(i); ++result, ++it) {
        if (it->length() > 0U) {
            tokens.push_back(static_cast<TOKENS>(result));
            break;
        }
    }
});

match_results<string::const_reverse_iterator> sm;

if(regex_search(crbegin(input), crend(input), sm, regex{ tokens.back() == SUBTRACTION ? "^\\s*\\d+\\s*-\\s*(-?)" : "^\\s*\\d+\\s*(-?)" })) {
    tokens.push_back(sm[1].length() == 0 ? NON_NEGATIVE_NUMBER : NEGATIVE_NUMBER);
}

Levande exempel

Ett anmärkningsvärt gotcha med regex iteratorer är att regex argumentet måste vara ett L-värde, ett R-värde fungerar inte: Visual Studio regex_iterator Bug?

Dela upp en sträng

std::vector<std::string> split(const std::string &str, std::string regex)
{
    std::regex r{ regex };
    std::sregex_token_iterator start{ str.begin(), str.end(), r, -1 }, end;
    return std::vector<std::string>(start, end);
}
split("Some  string\t with whitespace ", "\\s+"); // "Some", "string", "with", "whitespace"

Kvantifierare

Låt oss säga att vi har fått const string input som ett telefonnummer som ska valideras. Vi kan börja med att kräva en numerisk ingång med en kvantifierare med noll eller mer : regex_match(input, regex("\\d*")) eller en eller flera kvantifierare : regex_match(input, regex("\\d+")) Men båda dessa verkligen kommer till kort om input innehåller en ogiltig numerisk sträng som: "123" Låt oss använda en n eller mer kvantifierare för att säkerställa att vi får minst sju siffror:

regex_match(input, regex("\\d{7,}"))

Detta garanterar att vi får åtminstone ett telefonnummer med siffror, men input kan också innehålla en numerisk sträng som är för lång som: "123456789012". Så släpper med en kvantifierare mellan n och m så att input är minst 7 siffror men inte mer än 11:

regex_match(input, regex("\\d{7,11}"));

Detta kommer oss närmare, men olagliga numeriska strängar som ligger i intervallet [7, 11] accepteras fortfarande, som: "123456789" Så låt oss göra landskoden valfri med en lat kvantifierare :

regex_match(input, regex("\\d?\\d{7,10}"))

Det är viktigt att notera att den lata kvantifieraren matchar så få tecken som möjligt , så det enda sättet som detta tecken kommer att matchas är om det redan finns 10 tecken som har matchats av \d{7,10} . (För att matcha det första tecknet girigt skulle vi behöva göra: \d{0,1} .) Den lata kvantifieraren kan läggas till någon annan kvantifierare.

Nu, hur skulle vi göra områdeskoden valfri och bara acceptera en landskod om områdekoden fanns?

regex_match(input, regex("(?:\\d{3,4})?\\d{7}"))

I detta slutliga regex kräver \d{7} 7 siffror. Dessa sju siffror föregås valfritt av antingen 3 eller 4 siffror.

Observera att vi inte bifogade den lata kvantifieraren : \d{3,4}?\d{7} , \d{3,4}? skulle ha matchat antingen 3 eller 4 tecken, föredrar 3. Istället gör vi gruppmatchningen som inte fångar högst en gång, och föredrar att inte matcha. Orsakar en missanpassning om input inte inkluderade riktnummer som: "1234567".


Som avslutning på kvantifieringsämnet vill jag nämna det andra bifogade kvantifieraren som du kan använda, den besittande kvantifieraren . Antingen kan den lata kvantifieraren eller den besittande kvantifieraren läggas till vilken kvantifierare som helst. Den besittande kvantifierarens enda funktion är att hjälpa regexmotorn genom att berätta det, ta girigt med dessa karaktärer och aldrig ge upp dem, även om det får regexet att misslyckas . Detta till exempel har inte mycket mening: regex_match(input, regex("\\d{3,4}+\\d{7})) Eftersom en input som:" 1234567890 "inte skulle matchas som \d{3,4}+ kommer alltid att matcha 4 tecken även om matchning 3 skulle ha gjort det möjligt för regex att lyckas.
Den besittande kvantifieraren används bäst när det kvantifierade togetet begränsar antalet matchbara tecken . Till exempel:

regex_match(input, regex("(?:.*\\d{3,4}+){3}"))

Kan användas för att matcha om input innehåller något av följande:

123 456 7890
123-456-7890
(123)456-7890
(123) 456 - 7890

Men när denna regex verkligen lyser är när input innehåller en olaglig input:

12345 - 67890

Utan den besittande kvantifieraren måste regex-motorn gå tillbaka och testa varje kombination av .* Och antingen 3 eller 4 tecken för att se om den kan hitta en matchbar kombination. Med den besittande kvantifieraren startar regexen där den andra besittande kvantifieraren slutade, tecknet '0' och regex-motorn försöker justera .* att låta \d{3,4} matcha; när det inte kan regexen bara misslyckas, görs ingen backspårning för att se om tidigare .* Justering kunde ha möjliggjort en matchning.

ankare

C ++ ger endast fyra ankare:

  • ^ vilket säger att strängen startar
  • $ som hävdar slutet på strängen
  • \b som hävdar ett \W tecken eller strängens början eller slut
  • \B som hävdar en \w karaktär

Låt oss till exempel säga att vi vill fånga ett nummer med dess tecken:

auto input = "+1--12*123/+1234"s;
smatch sm;

if(regex_search(input, sm, regex{ "(?:^|\\b\\W)([+-]?\\d+)" })) {

    do {
        cout << sm[1] << endl;
        input = sm.suffix().str();
    } while(regex_search(input, sm, regex{ "(?:^\\W|\\b\\W)([+-]?\\d+)" }));
}

Levande exempel

En viktig anmärkning här är att ankaret inte konsumerar några tecken.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow