2016-03-19 29 views
10

A partire da C++ 11 le intestazioni <regex> definiscono le funzioni std::regex_match, std::regex_search e std::regex_replace in §28.11. Immagino ci sia un motivo valido per queste funzioni di non essere noexcept, ma non sono riuscito a trovare alcun riferimento a ciò che questi potrebbero lanciare o perché.Come gestire o evitare eccezioni dalle funzioni di corrispondenza C++ 11 <regex> (§28.11)?

  1. Quali tipi di eccezioni possono generare queste funzioni?
  2. Quali condizioni di runtime causano il lancio di queste eccezioni?
    • Lo standard garantisce che per alcuni insiemi di argomenti queste funzioni non vengano mai generate, ad es. si assicura che regex_match(anyString, regex(".")) non lanci mai?

PS: Dal momento che alcune di queste eccezioni probabilmente ereditano da std::runtime_error, hanno might throw std::bad_alloc during their construction.

+1

C'è l'ovvio ['regex_error'] (http://en.cppreference.com/w/cpp/regex/regex_error) – MSalters

+0

Ehi amico, non penso che riuscirai a muoverti gestione delle eccezioni per le funzioni di ricerca/corrispondenza/sostituzione. Per la compilazione probabilmente lo puoi fare. Sto usando e assumendo la gestione delle eccezioni di Boost :: Regex come guida perché, diciamocelo, la regex di C++ 11 è originata dal motore boost :: regex. La visualizzazione del codice boost è più facile da decifrare. Se non gestisci le eccezioni generate, il sistema operativo lo gestirà. Se pensi che la definizione di _noexcept_ (ovvero: BOOST_NO_EXCEPTIONS) interromperà i lanci di runtime durante l'esecuzione della loro implementazione, ti sbaglieresti. – sln

+1

(con't) L'eccezione principale di queste funzioni è _ran_out_of_stack_ durante la ricorsione interna. Anche l'impostazione dell'equivalente BOOST_REGEX_NON_RECURSIVE (il modo più sicuro, ma più lento) potrebbe ancora generare un lancio. È meglio catturare questi dati piuttosto che ottenere un messaggio oscuro del sistema. In profondità nelle viscere di trovare/abbinare/sostituire è il _imp_ di queste funzioni che possono _catch_ e ripensare tutto. L'eccezione può provenire dal sistema operativo o da qualsiasi luogo. Anche la cattura non garantisce che il thread non si blocchi a causa della ricorsione infinita. – sln

risposta

2

C++ 11 §28.6 stati

La classe regex_error definisce il tipo di oggetti lanciati come eccezioni a segnalare errori dalla libreria di espressione regolare.

Ciò significa che la libreria <regex> non deve generare altro da sola. È corretto che la costruzione di un regex_error che eredita da runtime_error possa generare bad_alloc durante la costruzione a causa di condizioni di esaurimento della memoria, pertanto è necessario verificarlo nel codice di gestione degli errori. Sfortunatamente, ciò rende impossibile determinare quale costruzione di regex_error lanci effettivamente bad_alloc.

Per regolare algoritmi espressioni in §28.11 si afferma in §28.11.1 che

Gli algoritmi descritti in questa sottoclausola possono un'eccezione di tipo regex_error. Se viene generata una tale eccezione e, e.code() deve restituire regex_constants::error_complexity o regex_-constants::error_stack.

Ciò significa che se le funzioni in §28.11 generano mai uno regex_error, deve contenere uno di questi codici e nient'altro. Tuttavia, tieni presente che anche le cose che passi alla libreria <regex>, come ad esempio gli allocatori ecc. Possono essere generate, ad es. l'allocatore di match_results che potrebbe attivarsi se i risultati vengono aggiunti al contenitore match_results specificato. Si noti inoltre che §28.11 ha funzioni abbreviate che "come se" costruiscono match_results, come

template <class BidirectionalIterator, class charT, class traits> 
bool regex_match(BidirectionalIterator first, BidirectionalIterator last, 
       const basic_regex<charT, traits> & e, 
       regex_constants::match_flag_type flags = 
       regex_constants::match_default); 

template <class BidirectionalIterator, class charT, class traits> 
bool regex_search(BidirectionalIterator first, BidirectionalIterator last, 
        const basic_regex<charT, traits> & e, 
        regex_constants::match_flag_type flags = 
        regex_constants::match_default); 

e possibilmente altri. Dal momento che tale potrebbe costruire e utilizzare match_results con lo standard allocator internamente, è possibile che vengano lanciati lanci di qualsiasi cosa. Pertanto il tuo semplice esempio di regex_match(anyString, regex(".")) potrebbe anche essere generato a causa della costruzione e dell'utilizzo dell'allocatore predefinito.

altro avvertimento da notare che per alcuni <regex> funzioni e classi è attualmente impossibile determinare se un bad_alloc generato dal alcuni allocatore o durante la costruzione di un'eccezione regex_error.

In generale, se avete bisogno di qualcosa con specifiche migliori, evitate di usare <regex>. Se si richiede una semplice corrispondenza di modelli, è meglio ruotare le proprie funzioni di corrispondenza/ricerca/sostituzione sicure, poiché è impossibile limitare le espressioni regolari per evitare tali eccezioni in un modo portatile o compatibile con i contratti di trasporto, anche utilizzando un'espressione regolare vuota "" potrebbe darti un'eccezione.

PS: Si noti che lo standard C++ 11 è scritto piuttosto male in alcuni aspetti, mancando di riferimenti incrociati completi. Per esempio. non c'è alcun avviso esplicito sotto le clausole per i metodi di match_results per lanciare qualsiasi cosa, mentre §28.10.1.1 stati (sottolineatura mia):

In tutti match_results costruttori, una copia della tesi Allocator devono essere utilizzati per qualsiasi memoria l'allocazione eseguita dalle funzioni del costruttore o membro durante il ciclo di vita dell'oggetto.

Quindi fai attenzione quando leggi gli standard come un avvocato! ;-)

+0

WOW! Esattamente la risposta che stavo cercando! Grazie mille per lo sforzo, questo mi fa risparmiare un sacco di tempo! – jotik

0

This link here might help. Come puoi vedere la maggior parte di questi sono espressioni regolari non valide, più che input non validi (che dovrebbero e non lanciano errori, semplicemente non corrispondono.

Passando attraverso lo here, posso vedere che regex_replace e il costruttore di regex può lanciare uno dei tipi di eccezione regex_error.Ho visto anche alcune eccezioni relative alla memoria, ma come detto queste sono runtime e potrebbero essere lanciate da qualsiasi pezzo di codice. Poiché la documentazione non fornisce nient'altro, l'unico modo per trovare questo sarebbe dal codice stesso.

+0

Potrebbe essere d'aiuto, ma una buona risposta completa su StackOverflow mi aiuterebbe (e altri) molto di più. – jotik

+0

Queste funzioni possono anche lanciare qualcosa di diverso da 'regex_error'? – jotik

+0

Come tutte le funzioni, possono essere generate altre eccezioni, ma non espressioni regolari specifiche. Ad esempio, qualcosa può sempre andare storto e ottenere un'eccezione aritmetica o nulla che non è stata gestita e generata a causa di un bug nel codice della libreria regex. –

0

Sede pp735-6 di Josuttis' 'il C++ standard Library' 2nd Edition. Ecco un elenco di eccezioni, ciascuna con una spiegazione del testo nelle prossime due linee

std::regex_constants::error_collate: 
"error_collate: " 
"regex has invalid collating element name"; 
std::regex_constants::error_ctype: 
"error_ctype: " 
"regex has invalid character class name"; 
std::regex_constants::error_escape: 
"error_escape: " 
"regex has invalid escaped char. or trailing escape"; 
std::regex_constants::error_backref: 
"error_backref: " 
"regex has invalid back reference"; 
std::regex_constants::error_brack: 
"error_brack: " 
"regex has mismatched ’[’ and ’]’"; 
std::regex_constants::error_paren: 
"error_paren: " 
"regex has mismatched ’(’ and ’)’"; 
std::regex_constants::error_brace: 
"error_brace: " 
"regex has mismatched ’{’ and ’}’"; 
std::regex_constants::error_badbrace: 
"error_badbrace: " 
"regex has invalid range in {} expression"; 
std::regex_constants::error_range: 
"error_range: " 
"regex has invalid character range, such as ’[b-a]’"; 
std::regex_constants::error_space: 
"error_space: " 
"insufficient memory to convert regex into finite state"; 
std::regex_constants::error_badrepeat: 
"error_badrepeat: " 
"one of *?+{ not preceded by valid regex"; 
std::regex_constants::error_complexity: 
"error_complexity: " 
"complexity of match against regex over pre-set level"; 
std::regex_constants::error_stack: 
"error_stack: " 
"insufficient memory to determine regex match"; 
+2

Tecnicamente queste non sono eccezioni, ma costanti. Poor OO design qui; dover fare un "cambio" all'interno di un "catch" è piuttosto spiacevole. – MSalters

4

regex_error è l'unica eccezione citata come generata da una qualsiasi delle classi o degli algoritmi in <regex>. Esistono due categorie fondamentali di errori: espressioni regolari non formattate e mancata elaborazione della corrispondenza.

I costruttori per basic_regex può lanciare una regex_error (come per [re.regex.construct] \3, \7, \14, e \17) se l'argomento (o sequenza) approvata nel "non è un'espressione regolare valida." Lo stesso è vero se si tenta di assegnare un basic_regex a un'espressione regolare non valida ([re.regex.assign]/15).

Separatamente da quello, gli algoritmi possono anche buttare regex_error ([re.except]/1):

Le funzioni descritte in questa segnalare errori clausola gettando eccezioni di tipo regex_error. Se viene generata una tale eccezione e, e.code() deve restituire regex_constants::error_complexity o regex_constants::error_stack.

cui tali due codici di errore significano ([re.err]):

error_complexity: La complessità di un tentativo partita con un'espressione regolare superamento di un valore prefissato.
error_stack: la memoria non era sufficiente per determinare se l'espressione regolare potesse corrispondere alla sequenza di caratteri specificata.

+0

Penso che [§28.11.1] (http://eel.is/c++draft/re.except#1) risponda meglio alla mia domanda. L'inglese non è la mia lingua madre, ma la formulazione del §28.11.1 sembra lasciare aperta la possibilità che vengano lanciati altri tipi di eccezioni. Hai un commento su questo? Non mi importa dei costruttori, funziona solo nel §28.11, quindi chiedi gentilmente di basare la tua risposta intorno al §28.11. – jotik

+1

@jotik Dire che questo tipo di eccezione può essere lanciato in nessun modo implica che possa essere lanciato anche un diverso tipo di eccezione. – Barry

+0

Ok. Ma è possibile garantire che non si buttino mai? Cioè in base allo standard (non alle implementazioni), è possibile costruire espressioni regolari con le quali le funzioni in §28.11 non vengono mai lanciate? Secondo, ho ragione, se dico che queste funzioni vengono lanciate solo se viene superato un limite di risorse? – jotik

1

Credo che questo è ciò che le eccezioni si dovrebbe gestire.
Per la compilazione ci sono 3 eccezioni.
Per una ricerca/partita/sostituire probabilmente solo bisogno di gestire 2.

Btw, se non si gestire le eccezioni il modo descritto qui di seguito, quindi il codice
sarà cieca, e non significava per consumo umano.

std::regex Regex; 

bool CompileRegex(std::string& strRx, unsigned int rxFlags) 
{ 
    try 
    { 
     Regex.assign(strRx, rxFlags); 
    } 
    catch (std::regex_error & e) 
    { 
      // handle e 
     return false; 
    } 
    catch (std::out_of_range & e) 
    { 
      // handle e 
     return false; 
    } 
    catch (std::runtime_error & e) 
    { 
      // handle e 
     return false; 
    } 
    return true; 
} 

bool UseRegex(std::string& strSource, std::string& strOut, std::string strReplace) 
{ 
    try 
    { 
    if (std::regex::regex_search(strSource, _match, Regex) 
    {} 
    // or 
    if (strOut = std::regex::regex_replace(strSource, Regex, strReplace)) 
    {} 
    } 
    catch (std::out_of_range & e) 
    { 
      // handle e 
     return false; 
    } 
    catch (std::runtime_error & e) 
    { 
      // handle e 
     return false; 
    } 
    return true;  
} 
Problemi correlati