C ++

Noções básicas de expressão regular em C ++

Noções básicas de expressão regular em C ++
Considere a seguinte frase entre aspas:

"Aqui está o meu homem."

Esta string pode estar dentro do computador, e o usuário pode querer saber se ela contém a palavra “man”. Se tiver a palavra homem, ele pode querer mudar a palavra “homem” para “mulher”; de modo que a string deve ser:

"Aqui está minha mulher."

Existem muitos outros desejos como esses do usuário do computador; alguns são complexos. Expressão regular, abreviado, regex, é o assunto para lidar com esses problemas pelo computador. C ++ vem com uma biblioteca chamada regex. Portanto, um programa C ++ para lidar com regex deve começar com:

#incluir
#incluir
usando namespace std;

Este artigo explica noções básicas de expressões regulares em C++.

Conteúdo do Artigo

  • Fundamentos da expressão regular
  • Padrão
  • Classes de personagens
  • Espaços em branco correspondentes
  • O período (.) no padrão
  • Repetições correspondentes
  • Alternância de correspondência
  • Início ou Fim da Correspondência
  • Agrupamento
  • As constantes icase e regex_constants multilinhas
  • Combinando o alvo inteiro
  • O objeto match_results
  • Posição da partida
  • Pesquisar e substituir
  • Conclusão

Fundamentos da expressão regular

Regex

Uma string como “Aqui está meu homem."Acima é a sequência alvo ou string alvo ou simplesmente, alvo. “Man”, que foi pesquisado, é a expressão regular, ou simplesmente regex.

Coincidindo

Diz-se que a correspondência ocorre quando a palavra ou frase que está sendo pesquisada é localizada. Após a correspondência, uma substituição pode ocorrer. Por exemplo, depois que "homem" for localizado acima, ele pode ser substituído por "mulher".

Correspondência Simples

O programa a seguir mostra como a palavra "homem" é combinada.

#incluir
#incluir
usando namespace std;
int main ()

regex reg ("homem");
if (regex_search ("Aqui está o meu homem.", reg))
cout << "matched" << endl;
senão
cout << "not matched" << endl;
return 0;

A função regex_search () retorna verdadeiro se houver uma correspondência e retorna falso se não ocorrer nenhuma correspondência. Aqui, a função leva dois argumentos: o primeiro é a string de destino e o segundo é o objeto regex. A própria regex é "man", entre aspas duplas. A primeira instrução na função main () forma o objeto regex. Regex é um tipo e reg é o objeto regex. A saída do programa acima é "combinada", pois "man" é visto na string de destino. Se "man" não fosse visto no destino, regex_search () teria retornado falso e a saída teria sido "incompatível".

A saída do seguinte código é “não correspondente”:

regex reg ("homem");
if (regex_search ("Aqui está minha criação.", reg))
cout << "matched" << endl;
senão
cout << "not matched" << endl;

Não correspondeu porque a regex "man" não pôde ser encontrada em toda a string de destino, "Aqui está minha criação."

Padrão

A expressão regular, "homem" acima, é muito simples. Regexes geralmente não são tão simples. Expressões regulares têm metacaracteres. Metacaracteres são caracteres com significados especiais. Um metacaractere é um personagem sobre personagens. Os metacaracteres C ++ regex são:

^ $ \ . * + ? () [] |

Um regex, com ou sem metacaracteres, é um padrão.

Classes de personagens

Colchetes

Um padrão pode ter caracteres entre colchetes. Com isso, uma posição particular na string alvo corresponderia a qualquer um dos caracteres dos colchetes. Considere os seguintes alvos:

"O gato esta na sala."
"O morcego está na sala."
"O rato está na sala."

A regex, [cbr] em corresponderia a cat no primeiro destino. Seria igualar o morcego no segundo alvo. Corresponderia ao rato no terceiro alvo. Isso ocorre porque "gato" ou "morcego" ou "rato" começa com 'c' ou 'b' ou 'r'. O seguinte segmento de código ilustra isso:

regex reg ("[cbr] em");
if (regex_search ("O gato está na sala.", reg))
cout << "matched" << endl;
if (regex_search ("O morcego está na sala.", reg))
cout << "matched" << endl;
if (regex_search ("O rato está na sala.", reg))
cout << "matched" << endl;

O resultado é:

coincide
coincide
coincide

Gama de personagens

A classe, [cbr] no padrão [cbr], corresponderia a vários caracteres possíveis no destino. Corresponderia a 'c' ou 'b' ou 'r' no alvo. Se o alvo não tiver nenhum 'c' ou 'b' ou 'r', seguido por "em", não haveria correspondência.

Algumas possibilidades como 'c' ou 'b' ou 'r' existem em um intervalo. O intervalo de dígitos, de 0 a 9, tem 10 possibilidades, e o padrão para isso é [0-9]. O intervalo de letras minúsculas, de a a z, tem 26 possibilidades, e o padrão para isso é [a-z]. A faixa de letras maiúsculas, de A a Z, tem 26 possibilidades, e o padrão para isso é [A-Z]. - não é oficialmente um metacaractere, mas entre colchetes, indica um intervalo. Portanto, o seguinte produz uma correspondência:

if (regex_search ("ID6id", regex ("[0-9]")))
cout << "matched" << endl;

Observe como a regex foi construída como o segundo argumento. A correspondência ocorre entre o dígito, 6 no intervalo, 0 a 9, e o 6 no destino, “ID6id”. O código acima é equivalente a:

if (regex_search ("ID6id", regex ("[0123456789]")))
cout << "matched" << endl;

O código a seguir produz uma correspondência:

char str [] = "ID6iE";
if (regex_search (str, regex ("[a-z]")))
cout << "matched" << endl;

Observe que o primeiro argumento aqui é uma variável de string e não o literal de string. A correspondência é entre 'i' em [a-z] e 'i' em “ID6iE”.

Não se esqueça que um intervalo é uma classe. Pode haver texto à direita do intervalo ou à esquerda do intervalo no padrão. O código a seguir produz uma correspondência:

if (regex_search ("ID2id é um ID ", regex (" ID [0-9] id ")))
cout << "matched" << endl;

A correspondência é entre “ID [0-9] id” e “ID2id”. O resto da string de destino, "é um ID", não é correspondido nesta situação.

Conforme usado no assunto da expressão regular (regexes), a palavra classe na verdade significa um conjunto. Ou seja, um dos personagens do conjunto deve corresponder.

Observação: o hífen - é um metacaractere apenas entre colchetes, indicando um intervalo. Não é um metacaractere no regex, fora dos colchetes.

Negação

Uma classe incluindo um intervalo pode ser negada. Ou seja, nenhum dos personagens do conjunto (classe) deve corresponder. Isso é indicado com o metacaractere ^ no início do padrão de classe, logo após o colchete de abertura. Portanto, [^ 0-9] significa combinar o caractere na posição apropriada no destino, que não é nenhum caractere no intervalo, de 0 a 9, inclusive. Portanto, o código a seguir não produzirá uma correspondência:

if (regex_search ("0123456789101112", regex ("[^ 0-9]")))
cout << "matched" << endl;
senão
cout << "not matched" << endl;

Um dígito no intervalo de 0 a 9 pode ser encontrado em qualquer uma das posições da string de destino, “0123456789101112,”; então não há correspondência - negação.

O código a seguir produz uma correspondência:

if (regex_search ("ABCDEFGHIJ", regex ("[^ 0-9]")))
cout << "matched" << endl;

Nenhum dígito foi encontrado no destino, “ABCDEFGHIJ,”; então há uma correspondência.

[a-z] é um intervalo fora de [^ a-z]. E então [^ a-z] é a negação de [a-z].

[A-Z] é um intervalo fora de [^ A-Z]. E então [^ A-Z] é a negação de [A-Z].

Existem outras negações.

Espaços em branco correspondentes

"ou \ t ou \ r ou \ n ou \ f é um caractere de espaço em branco. No código a seguir, o regex, “\ n” corresponde a '\ n' no destino:

if (regex_search ("Da linha um.\ r \ nDa linha dois.", regex (" \ n ")))
cout << "matched" << endl;

Combinando qualquer caractere de espaço em branco

O padrão ou classe para corresponder a qualquer caractere de espaço em branco é, [\ t \ r \ n \ f]. No código a seguir, "é correspondido:

if (regex_search ("um dois", regex ("[\ t \ r \ n \ f]")))
cout << "matched" << endl;

Combinando qualquer caractere sem espaço em branco

O padrão ou classe para corresponder a qualquer caractere diferente de espaço em branco é, [^ \ t \ r \ n \ f]. O código a seguir produz uma correspondência porque não há nenhum espaço em branco no destino:

if (regex_search ("1234abcd", regex ("[^ \ t \ r \ n \ f]")))
cout << "matched" << endl;

O período (.) no padrão

O período (.) no padrão corresponde a qualquer caractere incluindo ele mesmo, exceto \ n, no destino. Uma correspondência é produzida no seguinte código:

if (regex_search ("1234abcd", regex (".")))
cout << "matched" << endl;

Nenhum resultado correspondente no código a seguir porque o destino é “\ n”.

if (regex_search ("\ n", regex (".")))
cout << "matched" << endl;
senão
cout << "not matched" << endl;

Nota: dentro de uma classe de caractere com colchetes, o ponto não tem nenhum significado especial.

Repetições correspondentes

Um caractere ou grupo de caracteres pode ocorrer mais de uma vez dentro da string de destino. Um padrão pode corresponder a esta repetição. Os metacaracteres, ?, *, + e são usados ​​para combinar a repetição no alvo. Se x é um caractere de interesse na string de destino, os metacaracteres têm os seguintes significados:

x *: significa corresponder a 'x' 0 ou mais vezes, i.e., qualquer número de vezes
x +: significa corresponder a 'x' 1 ou mais vezes, i.e., pelo menos uma vez
x? : significa corresponder 'x' 0 ou 1 vez
x n,: significa corresponder a 'x' pelo menos n ou mais vezes. Observe a vírgula.
x n: corresponde a 'x' exatamente n vezes
x n, m: corresponde a 'x' pelo menos n vezes, mas não mais do que m vezes.

Esses metacaracteres são chamados de quantificadores.

Ilustrações

*

O * corresponde ao caractere anterior ou ao grupo anterior, nenhuma ou mais vezes. “O *” corresponde a 'o' em “cão” da string alvo. Também corresponde a “oo” em “livro” e “procurando”. O regex, “o *” corresponde a “boooo” em “The animal booooed.”. Nota: “o *” corresponde a “dig”, onde 'o' ocorre zero (ou mais).

+

O + corresponde ao caractere anterior ou ao grupo anterior, 1 ou mais vezes. Compare-o com zero ou mais vezes para *. Portanto, a regex, “e +” corresponde a 'e' em “comer”, onde 'e' ocorre uma vez. “E +” também corresponde a “ee” em “ovelha”, onde 'e' ocorre mais de uma vez. Nota: “e +” não corresponderá a “dig” porque em “dig”, 'e' não ocorre pelo menos uma vez.

?

O ? corresponde ao caractere anterior ou grupo anterior, 0 ou 1 vez (e não mais). Então, “e?”Corresponde a“ dig ”porque 'e' ocorre em“ dig ”, tempo zero. “E?”Corresponde a“ set ”porque 'e' ocorre em“ set ”, uma vez. Nota: “e?”Ainda corresponde a“ ovelha ”; embora haja dois 'e's em "ovelhas". Há uma nuance aqui - veja mais tarde.

n,

Corresponde a pelo menos n repetições consecutivas de um caractere anterior ou grupo anterior. Portanto, a regex, "e 2," corresponde aos dois 'e's no destino, "ovelha", e os três' e's no destino "sheeep". “E 2,” não corresponde a “set”, porque “set” tem apenas um 'e'.

n

Corresponde exatamente a n repetições consecutivas de um caractere anterior ou grupo anterior. Portanto, a regex, “e 2” corresponde aos dois 'e's no destino, “ovelha”. “E 2” não corresponde a “set” porque “set” tem apenas um 'e'. Bem, “e 2” corresponde a dois 'e's no alvo, “sheeep”. Há uma nuance aqui - veja mais tarde.

n, m

Corresponde a várias repetições consecutivas de um caractere anterior ou grupo anterior, em qualquer lugar de n a m, inclusive. Portanto, “e 1,3” não corresponde a nada em “dig”, que não tem 'e'. Corresponde ao um 'e' em “conjunto”, os dois 'e's em “ovelha”, os três' e's em “sheeep” e três 'e's em “sheeeep”. Há uma nuance na última partida - veja mais tarde.

Alternância de correspondência

Considere a seguinte string de destino no computador.

“A fazenda tem porcos de diferentes tamanhos.”

O programador pode querer saber se este alvo tem “cabra” ou “coelho” ou “porco”. O código seria o seguinte:

char str [] = "A fazenda tem porcos de tamanhos diferentes.";
if (regex_search (str, regex ("cabra | coelho | porco")))
cout << "matched" << endl;
senão
cout << "not matched" << endl;

O código produz uma correspondência. Observe o uso do caractere de alternância, |. Pode haver duas, três, quatro e mais opções. C ++ tentará primeiro corresponder à primeira alternativa, "cabra", em cada posição de caractere na string de destino. Se não tiver sucesso com “cabra”, ele tenta a próxima alternativa, “coelho”. Se não tiver sucesso com “coelho”, ele tenta a próxima alternativa, “porco”. Se “pig” falhar, então C ++ passa para a próxima posição no alvo e começa com a primeira alternativa novamente.

No código acima, “pig” é correspondido.

Início ou Fim da Correspondência

Começo


Se ^ estiver no início da regex, o texto inicial da string de destino pode ser correspondido pela regex. No código a seguir, o início do destino é “abc”, que corresponde a:

if (regex_search ("abc e def", regex ("^ abc")))
cout << "matched" << endl;

Nenhuma correspondência ocorre no seguinte código:

if (regex_search ("Sim, abc e def", regex ("^ abc")))
cout << "matched" << endl;
senão
cout << "not matched" << endl;

Aqui, “abc” não está no início do destino.

Observação: o caractere circunflexo, '^', é um metacaractere no início da regex, correspondendo ao início da string de destino. Ainda é um metacaractere no início da classe de personagem, onde nega a classe.

Fim

Se $ estiver no final da regex, então o texto final da string de destino pode ser correspondido pela regex. No código a seguir, o final do destino é “xyz”, que corresponde a:

if (regex_search ("uvw e xyz", regex ("xyz $")))
cout << "matched" << endl;

Nenhuma correspondência ocorre no seguinte código:

if (regex_search ("uvw e xyz final", regex ("xyz $")))
cout << "matched" << endl;
senão
cout << "not matched" << endl;

Aqui, “xyz” não está no final do alvo.

Agrupamento

Os parênteses podem ser usados ​​para agrupar caracteres em um padrão. Considere o seguinte regex:

"um concerto (pianista)"

O grupo aqui é “pianista” rodeado pelos metacaracteres (e). Na verdade, é um subgrupo, enquanto "um concerto (pianista)" é todo o grupo. Considere o seguinte:

"O (pianista é bom)"

Aqui, o subgrupo ou subcadeia é “pianist is good”.

Sub-strings com partes comuns

Um contador é uma pessoa que cuida de livros. Imagine uma biblioteca com guarda-livros e estante. Suponha que uma das seguintes strings de destino esteja no computador:

“A biblioteca tem uma estante que é admirada.";
"Aqui está o contador.";
“O contador trabalha com a estante.";

Suponha que o interesse do programador não seja saber qual dessas frases está no computador. Ainda assim, seu interesse é saber se "estante" ou "guarda-livros" está presente em qualquer string de destino no computador. Nesse caso, sua regex pode ser:

"estante | contador."

Usando alternância.

Observe que "livro", que é comum a ambas as palavras, foi digitado duas vezes, nas duas palavras do padrão. Para evitar digitar “livro” duas vezes, o regex seria melhor escrito como:

"livro (estante | guardião)"

Aqui, o grupo, “shelf | keeper” O metacaractere de alternância ainda foi usado, mas não por duas palavras longas. Foi usado para as duas partes finais das duas palavras longas. C ++ trata um grupo como uma entidade. Então, C ++ irá procurar por “prateleira” ou “guardião” que vem imediatamente após “livro”. A saída do seguinte código é “correspondida”:

char str [] = "A biblioteca tem uma estante que é admirada.";
if (regex_search (str, regex ("book (shelf | keeper)")))
cout << "matched" << endl;

“Estante” e não “guarda-livros” foram combinados.

As constantes icase e regex_constants multilinhas

icase

A correspondência diferencia maiúsculas de minúsculas por padrão. No entanto, pode ser indiferente a maiúsculas. Para fazer isso, use a constante regex :: icase, como no código a seguir:

if (regex_search ("Feedback", regex ("feed", regex :: icase)))
cout << "matched" << endl;

A saída é "combinada". Portanto, “Feedback” com 'F' maiúsculo foi correspondido por “feed” com 'f' minúsculo. “Regex :: icase” tornou-se o segundo argumento do construtor regex (). Sem isso, a declaração não produziria uma correspondência.

Multilinha

Considere o seguinte código:

char str [] = "linha 1 \ nlinha 2 \ nlinha 3";
if (regex_search (str, regex ("^.* $ ")))
cout << "matched" << endl;
senão
cout << "not matched" << endl;

A saída é “não combinada”. O regex, “^.* $, ”Corresponde à string de destino do início ao fim. “.* ”Significa qualquer caractere, exceto \ n, zero ou mais vezes. Então, por causa dos caracteres de nova linha (\ n) no destino, não houve correspondência.

O alvo é uma string multilinha. Em ordem para '.'para corresponder ao caractere de nova linha, a constante “regex :: multiline” deve ser feita, o segundo argumento da construção regex (). O código a seguir ilustra isso:

char str [] = "linha 1 \ nlinha 2 \ nlinha 3";
if (regex_search (str, regex ("^.* $ ", regex :: multiline)))
cout << "matched" << endl;
senão
cout << "not matched" << endl;

Correspondência de toda a string de destino

Para corresponder a toda a string de destino, que não tem o caractere de nova linha (\ n), a função regex_match () pode ser usada. Esta função é diferente de regex_search (). O código a seguir ilustra isso:

char str [] = "primeiro segundo terço";
if (regex_match (str, regex (".*segundo.* ")))
cout << "matched" << endl;

Há uma correspondência aqui. No entanto, observe que a regex corresponde a toda a string de destino, e a string de destino não tem nenhum '\ n'.

O objeto match_results

A função regex_search () pode receber um argumento entre o destino e o objeto regex. Este argumento é o objeto match_results. Toda a string combinada (parte) e as sub-strings combinadas podem ser conhecidas com ela. Este objeto é um array especial com métodos. O tipo de objeto match_results é cmatch (para literais de string).

Obtenção de fósforos

Considere o seguinte código:

char str [] = "A mulher que você estava procurando!";
cmatch m;
if (regex_search (str, m, regex ("w.m.n ")))
cout << m[0] << endl;

A string de destino contém a palavra "mulher". A saída é “mulher ', que corresponde ao regex,“ w.m.n ”. No índice zero, a matriz especial contém a única correspondência, que é "mulher".

Com as opções de classe, apenas a primeira sub-string encontrada no destino é enviada para a matriz especial. O código a seguir ilustra isso:

cmatch m;
if (regex_search ("O rato, o gato, o morcego!", m, regex (" [bcr] at ")))
cout << m[0] << endl;
cout << m[1] << endl;
cout << m[2] << endl;

A saída é "rato" do índice zero. m [1] e m [2] estão vazios.

Com alternativas, apenas a primeira subcadeia encontrada no destino, é enviada para a matriz especial. O código a seguir ilustra isso:

if (regex_search ("O coelho, a cabra, o porco!", m, regex (" cabra | coelho | porco ")))
cout << m[0] << endl;
cout << m[1] << endl;
cout << m[2] << endl;

A saída é "coelho" do índice zero. m [1] e m [2] estão vazios.

Agrupamentos

Quando os grupos estão envolvidos, o padrão completo combinado vai para a célula zero da matriz especial. A próxima subcadeia encontrada vai para a célula 1; a subsequente seqüência de caracteres, vai para a célula 2; e assim por diante. O código a seguir ilustra isso:

if (regex_search ("Melhor livreiro hoje!", m, regex (" book ((sel) (ler)) ")))
cout << m[0] << endl;
cout << m[1] << endl;
cout << m[2] << endl;
cout << m[3] << endl;

O resultado é:

livreiro
vendedor
sel
ler

Observe que o grupo (vendedor) vem antes do grupo (sel).

Posição da partida

A posição de correspondência para cada substring na matriz cmatch pode ser conhecida. A contagem começa a partir do primeiro caractere da string alvo, na posição zero. O código a seguir ilustra isso:

cmatch m;
if (regex_search ("Melhor livreiro hoje!", m, regex (" book ((sel) (ler)) ")))
cout << m[0] << "->" << m.position(0) << endl;
cout << m[1] << "->" << m.position(1) << endl;
cout << m[2] << "->" << m.position(2) << endl;
cout << m[3] << "->" << m.position(3) << endl;

Observe o uso da propriedade position, com o índice da célula, como um argumento. O resultado é:

livreiro-> 5
vendedor-> 9
sel-> 9
ler-> 12

Pesquisar e substituir

Uma nova palavra ou frase pode substituir a correspondência. A função regex_replace () é usada para isso. No entanto, desta vez, a string onde ocorre a substituição é o objeto string, não o literal da string. Portanto, a biblioteca de strings deve ser incluída no programa. Ilustração:

#incluir
#incluir
#incluir
usando namespace std;
int main ()

string str = "Aqui, vem meu homem. Lá vai seu homem.";
string newStr = regex_replace (str, regex ("homem"), "mulher");
cout << newStr << endl;
return 0;

A função regex_replace (), conforme codificada aqui, substitui todas as correspondências. O primeiro argumento da função é o destino, o segundo é o objeto regex e o terceiro é a string de substituição. A função retorna uma nova string, que é o destino, mas tendo a substituição. O resultado é:

“Aí vem minha mulher. Lá vai sua mulher.”

Conclusão

A expressão regular usa padrões para combinar substrings na string de sequência de destino. Os padrões têm metacaracteres. Funções comumente usadas para expressões regulares C ++, são: regex_search (), regex_match () e regex_replace (). Um regex é um padrão entre aspas duplas. No entanto, essas funções tomam o objeto regex como um argumento e não apenas o regex. O regex deve ser transformado em um objeto regex antes que essas funções possam usá-lo.

O cursor pula ou se move aleatoriamente enquanto digita no Windows 10
Se você descobrir que o cursor do mouse pula ou se move por conta própria, de forma automática e aleatória ao digitar em um laptop ou computador com W...
Como reverter a direção de rolagem do Mouse e Touchpads no Windows 10
Mouse e Touchpads não apenas torna a computação mais fácil, mas mais eficiente e menos demorada. Não podemos imaginar uma vida sem esses dispositivos,...
Como alterar o ponteiro do mouse e tamanho do cursor, cor e esquema no Windows 10
O ponteiro do mouse e o cursor no Windows 10 são aspectos muito importantes do sistema operacional. Isso também pode ser dito para outros sistemas ope...