Limpar string com RegexComo fazer o parse de um array de string para um array multidimensional?REGEX - Como capturar blocos de CASE WHEN … ENDProblema com regex para UserAgent Androidregex parar caso o charactere logo em seguida seja outroComo dar um Regex antes de uma string? E selecionar?Regex para otimizar mudança nos códigos usando Notepad++Fitrar array PHPComo fazer esse regex?Substituição de lista com padrão em regexUsando REGEX em PHP para capturar qualquer número que não esteja dentro de aspas simples
Limpar string com Regex
Como fazer o parse de um array de string para um array multidimensional?REGEX - Como capturar blocos de CASE WHEN … ENDProblema com regex para UserAgent Androidregex parar caso o charactere logo em seguida seja outroComo dar um Regex antes de uma string? E selecionar?Regex para otimizar mudança nos códigos usando Notepad++Fitrar array PHPComo fazer esse regex?Substituição de lista com padrão em regexUsando REGEX em PHP para capturar qualquer número que não esteja dentro de aspas simples
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
Tenho a seguinte array em PHP:
[
"Opcao 01 - Frase aleatória - Menu Superior",
"Opcao 02 - Outra Frase aleatória - Menu Su",
"Opcao 03 - Mais 01 Frase - Menu",
"Opcao 04 - Mais Frase -",
"Opcao 05 - Frase Simples",
]
Preciso limpar ela para ficar assim:
01 - Frase aleatória",
02 - Outra Frase aleatória",
03 - Mais 01 Frase",
04 - Mais Frase",
05 - Frase Simples",
E tenho que fazer isto com regex. Como seria a sequência para este filtro?
php regex
|
mostrar mais 1 comentário
Tenho a seguinte array em PHP:
[
"Opcao 01 - Frase aleatória - Menu Superior",
"Opcao 02 - Outra Frase aleatória - Menu Su",
"Opcao 03 - Mais 01 Frase - Menu",
"Opcao 04 - Mais Frase -",
"Opcao 05 - Frase Simples",
]
Preciso limpar ela para ficar assim:
01 - Frase aleatória",
02 - Outra Frase aleatória",
03 - Mais 01 Frase",
04 - Mais Frase",
05 - Frase Simples",
E tenho que fazer isto com regex. Como seria a sequência para este filtro?
php regex
Já tentou isso sem aspas? "d+s+[-]s+w+s+d+"
– Park
9/03 às 0:44
Qual linguagem? você já tem algum contexto de codigo que não tem funcionado?
– Martins Luan
9/03 às 0:50
@Park olha eu acabei de tentar e não deu certo. Não traz nada de resposta. Até o w deu certo mas depois ja da erro. Obrigado
– Joao Nivaldo
9/03 às 0:57
@MartinsLuan vou usar no PHP.
– Joao Nivaldo
9/03 às 0:57
1
@hkotsubo feito amigo. Acho que melhorou agora. Obrigado pela dica.
– Joao Nivaldo
9/03 às 1:12
|
mostrar mais 1 comentário
Tenho a seguinte array em PHP:
[
"Opcao 01 - Frase aleatória - Menu Superior",
"Opcao 02 - Outra Frase aleatória - Menu Su",
"Opcao 03 - Mais 01 Frase - Menu",
"Opcao 04 - Mais Frase -",
"Opcao 05 - Frase Simples",
]
Preciso limpar ela para ficar assim:
01 - Frase aleatória",
02 - Outra Frase aleatória",
03 - Mais 01 Frase",
04 - Mais Frase",
05 - Frase Simples",
E tenho que fazer isto com regex. Como seria a sequência para este filtro?
php regex
Tenho a seguinte array em PHP:
[
"Opcao 01 - Frase aleatória - Menu Superior",
"Opcao 02 - Outra Frase aleatória - Menu Su",
"Opcao 03 - Mais 01 Frase - Menu",
"Opcao 04 - Mais Frase -",
"Opcao 05 - Frase Simples",
]
Preciso limpar ela para ficar assim:
01 - Frase aleatória",
02 - Outra Frase aleatória",
03 - Mais 01 Frase",
04 - Mais Frase",
05 - Frase Simples",
E tenho que fazer isto com regex. Como seria a sequência para este filtro?
php regex
php regex
editada 9/03 às 1:22
hkotsubo
11mil72253
11mil72253
perguntada 9/03 às 0:29
Joao NivaldoJoao Nivaldo
711719
711719
Já tentou isso sem aspas? "d+s+[-]s+w+s+d+"
– Park
9/03 às 0:44
Qual linguagem? você já tem algum contexto de codigo que não tem funcionado?
– Martins Luan
9/03 às 0:50
@Park olha eu acabei de tentar e não deu certo. Não traz nada de resposta. Até o w deu certo mas depois ja da erro. Obrigado
– Joao Nivaldo
9/03 às 0:57
@MartinsLuan vou usar no PHP.
– Joao Nivaldo
9/03 às 0:57
1
@hkotsubo feito amigo. Acho que melhorou agora. Obrigado pela dica.
– Joao Nivaldo
9/03 às 1:12
|
mostrar mais 1 comentário
Já tentou isso sem aspas? "d+s+[-]s+w+s+d+"
– Park
9/03 às 0:44
Qual linguagem? você já tem algum contexto de codigo que não tem funcionado?
– Martins Luan
9/03 às 0:50
@Park olha eu acabei de tentar e não deu certo. Não traz nada de resposta. Até o w deu certo mas depois ja da erro. Obrigado
– Joao Nivaldo
9/03 às 0:57
@MartinsLuan vou usar no PHP.
– Joao Nivaldo
9/03 às 0:57
1
@hkotsubo feito amigo. Acho que melhorou agora. Obrigado pela dica.
– Joao Nivaldo
9/03 às 1:12
Já tentou isso sem aspas? "d+s+[-]s+w+s+d+"
– Park
9/03 às 0:44
Já tentou isso sem aspas? "d+s+[-]s+w+s+d+"
– Park
9/03 às 0:44
Qual linguagem? você já tem algum contexto de codigo que não tem funcionado?
– Martins Luan
9/03 às 0:50
Qual linguagem? você já tem algum contexto de codigo que não tem funcionado?
– Martins Luan
9/03 às 0:50
@Park olha eu acabei de tentar e não deu certo. Não traz nada de resposta. Até o w deu certo mas depois ja da erro. Obrigado
– Joao Nivaldo
9/03 às 0:57
@Park olha eu acabei de tentar e não deu certo. Não traz nada de resposta. Até o w deu certo mas depois ja da erro. Obrigado
– Joao Nivaldo
9/03 às 0:57
@MartinsLuan vou usar no PHP.
– Joao Nivaldo
9/03 às 0:57
@MartinsLuan vou usar no PHP.
– Joao Nivaldo
9/03 às 0:57
1
1
@hkotsubo feito amigo. Acho que melhorou agora. Obrigado pela dica.
– Joao Nivaldo
9/03 às 1:12
@hkotsubo feito amigo. Acho que melhorou agora. Obrigado pela dica.
– Joao Nivaldo
9/03 às 1:12
|
mostrar mais 1 comentário
3 Respostas
3
ativas
mais antigas
votos
Tente o seguinte:
d+s+-[^-]*
Como você prefere sem os espaços, tente isso:
d+s+-[^-]*(?=s)
Há outras formas de você fazer isso:
1) d+s+-.*?(?=s+-|$) veja
2) d+s+-(?:s.*?(?=s+-)|.+) veja
3) (d+s+[-]s+.?(?=s+-)|d+s+[-].) veja
4) d+s+-(?:s+S*(?:s(?!s*-)S*)*|.+) mais eficiente que as outras. Veja
A quarta opção é muito eficiente porque os pedaços até um espaço em
branco são combinados em "lotes", as verificações de um hífen são
feitas somente quando um espaço em branco é encontrado.
Cara deu certinho a unica coisa é que ele ta pegando o ultimo espaçõ antes do -. Tem como remover este espaço do final?
– Joao Nivaldo
9/03 às 1:54
@Joao Nivaldo Dá sim, atualizei a resposta
– Park
9/03 às 1:57
1
Deu certinho agora. Muito obrigado.
– Joao Nivaldo
9/03 às 2:07
comentar |
Você pode usar a função preg_replace
para fazer a substituição.
A regex pode ser algo como ^w+ (d+ -[^-]+)( -.*)?$
:
- os marcadores
^
e$
são, respectivamente, o início e fim da string. Isso garante que estou verificando toda a string. - o atalho
w
significa "letras (de A a Z, maiúsculas ou minúsculas), números (de 0 a 9) ou o caractere_
" - o atalho
d
significa "qualquer dígito de 0 a 9" - o quantificador
+
significa "uma ou mais ocorrências". [^-]
é "qualquer caractere que não seja hífen".*
é "zero ou mais ocorrências de qualquer caractere", e o?
logo depois torna o trecho( -.*)
opcional (ou seja, pode ter um espaço, hífen e "qualquer coisa" no final da string)
Então a regex começa com w+
(uma ou mais ocorrências de letras, números ou _
), seguido de espaço, depois um ou mais números (d+
), espaço, hífen, vários caracteres que não são hífen (isso garante que só vai pegar até o próximo hífen), seguidos opcionalmente por espaço, hífen e .*
(zero ou mais ocorrências de qualquer coisa), e por fim o final da string.
O trecho d+ -[^-]+
está entre parênteses, e isso forma um grupo de captura. Isso quer dizer que o texto que corresponde a este trecho pode ser referenciado posteriormente.
No caso, como é o primeiro par de parênteses, o texto que for capturado estará disponível na variável especial $1
, que posso usar no segundo parâmetro do preg_replace
:
$textos = array(
"Opcao 01 - Frase aleatória - Menu Superior",
"Opcao 02 - Outra Frase aleatória - Menu Su",
"Opcao 03 - Mais 01 Frase - Menu",
"Opcao 04 - Mais Frase -",
"Opcao 05 - Frase Simples");
foreach($textos as $texto)
echo preg_replace('/^w+ (d+ -[^-]+)( -.*)?$/', '$1', $texto), PHP_EOL;
O resultado é:
01 - Frase aleatória
02 - Outra Frase aleatória
03 - Mais 01 Frase
04 - Mais Frase
05 - Frase Simples
Se quiser, pode passar o array inteiro para preg_replace
, que o retorno será outro array com as substituições feitas:
$textos = array(
"Opcao 01 - Frase aleatória - Menu Superior",
"Opcao 02 - Outra Frase aleatória - Menu Su",
"Opcao 03 - Mais 01 Frase - Menu",
"Opcao 04 - Mais Frase -",
"Opcao 05 - Frase Simples");
var_dump(preg_replace('/^w+ (d+ -[^-]+)( -.*)?$/', '$1', $textos));
Saída:
array(5)
[0]=>
string(21) "01 - Frase aleatória"
[1]=>
string(27) "02 - Outra Frase aleatória"
[2]=>
string(18) "03 - Mais 01 Frase"
[3]=>
string(15) "04 - Mais Frase"
[4]=>
string(18) "05 - Frase Simples"
Caracteres acentuados
Na regex acima, w
não considera caracteres acentuados, então se a string começar com "Opção", por exemplo, não funcionará. Outro detalhe é que w
também considera números e o caractere _
. Se quiser somente letras, uma opção é usar as propriedades Unicode (usando a categoria L
- que considera todas as letras, inclusive de outros alfabetos, como o japonês, coreano, cirílico, etc), não esquecendo de usar o modificador u
(logo depois da segunda /
na regex):
// trocar w por pL e adicionar a opção "u" na regex, para considerar letras acentuadas
var_dump(preg_replace('/^pL+ (d+ -[^-]+)( -.*)?$/u', '$1', $textos));
Se quiser deixar o w
, basta adicionar a opção u
(lembrando que o w
também considera números e o _
):
var_dump(preg_replace('/^w+ (d+ -[^-]+)( -.*)?$/u', '$1', $textos));
Espaços
As opções acima funcionam para quando há apenas um espaço separando as palavras, números e hífens.
Mas caso haja mais de um espaço separando essas partes, pode usar s+
(um ou mais espaços). Além disso, modifiquei um pouco a regex para o caso de ter mais de um espaço antes do segundo hífen (por exemplo, "Opção 01 - Frase aleatória - Menu Superior"
):
var_dump(preg_replace('/^w+s+(d+s+-s+([^-s]+(s+[^-s]+)*))(s+-.*)?$/u', '$1', $textos));
Para o trecho entre os dois hífens, usei [^-s]+(s+[^-s]+)*
:
[^-s]+
: uma ou mais ocorrências de qualquer coisa que não seja hífen nem espaço(s+[^-s]+)*
: zero ou mais ocorrências de "espaços, seguido de vários caracteres que não sejam hífen ou espaço"
Com isso, eu capturo o texto "Frase aleatória"
, sem o risco de pegar o segundo hífen, nem os espaços que tem antes dele (mas pegando os espaços entre as palavras). Pode parecer uma complicação extra, pois você pode pensar "por que não usar .*?
que é mais simples?". O que me leva a outro tópico: a eficiência de uma regex.
Eficiência
Apenas para efeito de comparação com a resposta do usuário @Park (que também está certa, não estou criticando, apenas comparando as soluções), a regex que sugeri é mais eficiente. O regex101.com possui uma ferramenta de debugging que é bem interessante para ver como a regex se comporta.
No caso da regex (d+s+[-]s+.*?(?=s+-)|d+s+[-].*)
, veja que ela leva entre 67 e 137 passos (dependendo da string) para encontrar um match. Já a regex que sugeri leva no máximo 21 passos. A segunda versão, com s+
em vez de espaço, leva no máximo 29 passos.
E caso a string não corresponda à regex, a que eu usei demora menos para perceber isso e reportar um no-match (53 passos contra 149 - a segunda versão, com s+
, também precisa de 53 passos).
Dito isso, obviamente estes resultados são estimativas e os números exatos dependem de como a engine interna do PHP é implementada: tanto os links do regex101.com que coloquei acima quanto as funções preg_xxx
usam uma engine PCRE (Perl Compatible Regular Expressions), mas dependendo da regex e das strings utilizadas, algumas linguagens fazem otimizações internas em alguns casos, por exemplo. Mesmo usando o mesmo tipo de regex (PCRE), os números podem variar de uma linguagem/engine/ferramenta para outra.
Mas de qualquer forma os números reais não devem mudar muito. A regex da outra resposta usa alternância (|
) (o que sempre faz ela tentar todas as alternativas, até uma dar certo) e .*?
, que faz a engine testar várias possibilidades (afinal, significa "zero ou mais ocorrências de qualquer caractere"), e isso faz com que ela execute vários passos adicionais (no caso de strings que não satisfazem a regex, ela precisa testar todas as possibilidades até ter certeza de que não dá mesmo).
A minha regex até usa .*
, mas é no final da string e dentro de um bloco opcional, o que reduz um pouco este overhead, além de não ter alternância (uma única alternativa a se testar em vez de duas) e usar [^-]
(qualquer caractere que não seja hífen), que gera menos possibilidades do que o .
(que é "qualquer caractere", o que aumenta exponencialmente as possibilidades, já que o próprio hífen pode ser incluído se a regex achar necessário).
O fato de eu ter usado ^
e $
também ajuda nesse sentido, pois sem eles a regex é testada novamente a cada posição da string, até encontrar o ponto em que ela é satisfeita. Usando ^
elimina esses passos a mais, pois ela já sabe que deve sempre buscar do início da string. Ou seja, vários detalhes que isoladamente parecem "bobos", mas juntos fazem diferença.
É claro que para uma quantidade pequena de strings curtas, a diferença será insignificante (provavelmente será de milissegundos ou até menos), mas se for lidar com uma grande quantidade de dados, pode ser que faça diferença. Inclusive, usar .*
pode causar um aumento exponencial de passos, dependendo do caso (aumentar 3 caracteres na string inválida, por exemplo, só adiciona mais 3 passos na minha regex (de 53 para 56, inclusive na segunda versão com s+
), enquanto na outra adiciona 15 (pula de 149 para 164)).
Não sei se você vai lidar com uma quantidade tão grande de dados a ponto de fazer alguma diferença no desempenho, mas de qualquer forma fica registrada a alternativa.
1
Vc sempre me surpreendendo com regex. Daria mais de um upvote se fosse possível! Kk
– LipESprY
9/03 às 19:25
comentar |
Você precisa usar a função chamada str_replace, fiz um exemplo pra você
<?php
function limpar_stringl($string) // replace para limpar variaveis Opcao 01 - Item 01 - Menu Superior
$string = str_replace('Opcao','', $string);
$string = str_replace(' - Menu Superior','', $string);
return $string;
echo limpar_stringl("Opcao 01 - Item 01 - Menu Superior");
- Sempre que quiser refatorar um novo caractere ou conjunto de caracteres palavras etc você vai precisar adicionar uma nova linha no codigo
- Relacionar o item
$string = str_replace('caractere ou palavra','', $string);
Eu preciso como disse fazer com o REGEX. Obrigado
– Joao Nivaldo
9/03 às 1:11
comentar |
Sua resposta
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "526"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Desenvolvido por u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Registre-se ou faça log-in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Registre-se usando o Google
Registre-se usando o Facebook
Registre-se usando Email e Senha
Publicar como convidado
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fpt.stackoverflow.com%2fquestions%2f367165%2flimpar-string-com-regex%23new-answer', 'question_page');
);
Publicar como convidado
Required, but never shown
3 Respostas
3
ativas
mais antigas
votos
3 Respostas
3
ativas
mais antigas
votos
ativas
mais antigas
votos
ativas
mais antigas
votos
Tente o seguinte:
d+s+-[^-]*
Como você prefere sem os espaços, tente isso:
d+s+-[^-]*(?=s)
Há outras formas de você fazer isso:
1) d+s+-.*?(?=s+-|$) veja
2) d+s+-(?:s.*?(?=s+-)|.+) veja
3) (d+s+[-]s+.?(?=s+-)|d+s+[-].) veja
4) d+s+-(?:s+S*(?:s(?!s*-)S*)*|.+) mais eficiente que as outras. Veja
A quarta opção é muito eficiente porque os pedaços até um espaço em
branco são combinados em "lotes", as verificações de um hífen são
feitas somente quando um espaço em branco é encontrado.
Cara deu certinho a unica coisa é que ele ta pegando o ultimo espaçõ antes do -. Tem como remover este espaço do final?
– Joao Nivaldo
9/03 às 1:54
@Joao Nivaldo Dá sim, atualizei a resposta
– Park
9/03 às 1:57
1
Deu certinho agora. Muito obrigado.
– Joao Nivaldo
9/03 às 2:07
comentar |
Tente o seguinte:
d+s+-[^-]*
Como você prefere sem os espaços, tente isso:
d+s+-[^-]*(?=s)
Há outras formas de você fazer isso:
1) d+s+-.*?(?=s+-|$) veja
2) d+s+-(?:s.*?(?=s+-)|.+) veja
3) (d+s+[-]s+.?(?=s+-)|d+s+[-].) veja
4) d+s+-(?:s+S*(?:s(?!s*-)S*)*|.+) mais eficiente que as outras. Veja
A quarta opção é muito eficiente porque os pedaços até um espaço em
branco são combinados em "lotes", as verificações de um hífen são
feitas somente quando um espaço em branco é encontrado.
Cara deu certinho a unica coisa é que ele ta pegando o ultimo espaçõ antes do -. Tem como remover este espaço do final?
– Joao Nivaldo
9/03 às 1:54
@Joao Nivaldo Dá sim, atualizei a resposta
– Park
9/03 às 1:57
1
Deu certinho agora. Muito obrigado.
– Joao Nivaldo
9/03 às 2:07
comentar |
Tente o seguinte:
d+s+-[^-]*
Como você prefere sem os espaços, tente isso:
d+s+-[^-]*(?=s)
Há outras formas de você fazer isso:
1) d+s+-.*?(?=s+-|$) veja
2) d+s+-(?:s.*?(?=s+-)|.+) veja
3) (d+s+[-]s+.?(?=s+-)|d+s+[-].) veja
4) d+s+-(?:s+S*(?:s(?!s*-)S*)*|.+) mais eficiente que as outras. Veja
A quarta opção é muito eficiente porque os pedaços até um espaço em
branco são combinados em "lotes", as verificações de um hífen são
feitas somente quando um espaço em branco é encontrado.
Tente o seguinte:
d+s+-[^-]*
Como você prefere sem os espaços, tente isso:
d+s+-[^-]*(?=s)
Há outras formas de você fazer isso:
1) d+s+-.*?(?=s+-|$) veja
2) d+s+-(?:s.*?(?=s+-)|.+) veja
3) (d+s+[-]s+.?(?=s+-)|d+s+[-].) veja
4) d+s+-(?:s+S*(?:s(?!s*-)S*)*|.+) mais eficiente que as outras. Veja
A quarta opção é muito eficiente porque os pedaços até um espaço em
branco são combinados em "lotes", as verificações de um hífen são
feitas somente quando um espaço em branco é encontrado.
editada 22/03 às 0:15
respondida 9/03 às 1:21
ParkPark
1409
1409
Cara deu certinho a unica coisa é que ele ta pegando o ultimo espaçõ antes do -. Tem como remover este espaço do final?
– Joao Nivaldo
9/03 às 1:54
@Joao Nivaldo Dá sim, atualizei a resposta
– Park
9/03 às 1:57
1
Deu certinho agora. Muito obrigado.
– Joao Nivaldo
9/03 às 2:07
comentar |
Cara deu certinho a unica coisa é que ele ta pegando o ultimo espaçõ antes do -. Tem como remover este espaço do final?
– Joao Nivaldo
9/03 às 1:54
@Joao Nivaldo Dá sim, atualizei a resposta
– Park
9/03 às 1:57
1
Deu certinho agora. Muito obrigado.
– Joao Nivaldo
9/03 às 2:07
Cara deu certinho a unica coisa é que ele ta pegando o ultimo espaçõ antes do -. Tem como remover este espaço do final?
– Joao Nivaldo
9/03 às 1:54
Cara deu certinho a unica coisa é que ele ta pegando o ultimo espaçõ antes do -. Tem como remover este espaço do final?
– Joao Nivaldo
9/03 às 1:54
@Joao Nivaldo Dá sim, atualizei a resposta
– Park
9/03 às 1:57
@Joao Nivaldo Dá sim, atualizei a resposta
– Park
9/03 às 1:57
1
1
Deu certinho agora. Muito obrigado.
– Joao Nivaldo
9/03 às 2:07
Deu certinho agora. Muito obrigado.
– Joao Nivaldo
9/03 às 2:07
comentar |
Você pode usar a função preg_replace
para fazer a substituição.
A regex pode ser algo como ^w+ (d+ -[^-]+)( -.*)?$
:
- os marcadores
^
e$
são, respectivamente, o início e fim da string. Isso garante que estou verificando toda a string. - o atalho
w
significa "letras (de A a Z, maiúsculas ou minúsculas), números (de 0 a 9) ou o caractere_
" - o atalho
d
significa "qualquer dígito de 0 a 9" - o quantificador
+
significa "uma ou mais ocorrências". [^-]
é "qualquer caractere que não seja hífen".*
é "zero ou mais ocorrências de qualquer caractere", e o?
logo depois torna o trecho( -.*)
opcional (ou seja, pode ter um espaço, hífen e "qualquer coisa" no final da string)
Então a regex começa com w+
(uma ou mais ocorrências de letras, números ou _
), seguido de espaço, depois um ou mais números (d+
), espaço, hífen, vários caracteres que não são hífen (isso garante que só vai pegar até o próximo hífen), seguidos opcionalmente por espaço, hífen e .*
(zero ou mais ocorrências de qualquer coisa), e por fim o final da string.
O trecho d+ -[^-]+
está entre parênteses, e isso forma um grupo de captura. Isso quer dizer que o texto que corresponde a este trecho pode ser referenciado posteriormente.
No caso, como é o primeiro par de parênteses, o texto que for capturado estará disponível na variável especial $1
, que posso usar no segundo parâmetro do preg_replace
:
$textos = array(
"Opcao 01 - Frase aleatória - Menu Superior",
"Opcao 02 - Outra Frase aleatória - Menu Su",
"Opcao 03 - Mais 01 Frase - Menu",
"Opcao 04 - Mais Frase -",
"Opcao 05 - Frase Simples");
foreach($textos as $texto)
echo preg_replace('/^w+ (d+ -[^-]+)( -.*)?$/', '$1', $texto), PHP_EOL;
O resultado é:
01 - Frase aleatória
02 - Outra Frase aleatória
03 - Mais 01 Frase
04 - Mais Frase
05 - Frase Simples
Se quiser, pode passar o array inteiro para preg_replace
, que o retorno será outro array com as substituições feitas:
$textos = array(
"Opcao 01 - Frase aleatória - Menu Superior",
"Opcao 02 - Outra Frase aleatória - Menu Su",
"Opcao 03 - Mais 01 Frase - Menu",
"Opcao 04 - Mais Frase -",
"Opcao 05 - Frase Simples");
var_dump(preg_replace('/^w+ (d+ -[^-]+)( -.*)?$/', '$1', $textos));
Saída:
array(5)
[0]=>
string(21) "01 - Frase aleatória"
[1]=>
string(27) "02 - Outra Frase aleatória"
[2]=>
string(18) "03 - Mais 01 Frase"
[3]=>
string(15) "04 - Mais Frase"
[4]=>
string(18) "05 - Frase Simples"
Caracteres acentuados
Na regex acima, w
não considera caracteres acentuados, então se a string começar com "Opção", por exemplo, não funcionará. Outro detalhe é que w
também considera números e o caractere _
. Se quiser somente letras, uma opção é usar as propriedades Unicode (usando a categoria L
- que considera todas as letras, inclusive de outros alfabetos, como o japonês, coreano, cirílico, etc), não esquecendo de usar o modificador u
(logo depois da segunda /
na regex):
// trocar w por pL e adicionar a opção "u" na regex, para considerar letras acentuadas
var_dump(preg_replace('/^pL+ (d+ -[^-]+)( -.*)?$/u', '$1', $textos));
Se quiser deixar o w
, basta adicionar a opção u
(lembrando que o w
também considera números e o _
):
var_dump(preg_replace('/^w+ (d+ -[^-]+)( -.*)?$/u', '$1', $textos));
Espaços
As opções acima funcionam para quando há apenas um espaço separando as palavras, números e hífens.
Mas caso haja mais de um espaço separando essas partes, pode usar s+
(um ou mais espaços). Além disso, modifiquei um pouco a regex para o caso de ter mais de um espaço antes do segundo hífen (por exemplo, "Opção 01 - Frase aleatória - Menu Superior"
):
var_dump(preg_replace('/^w+s+(d+s+-s+([^-s]+(s+[^-s]+)*))(s+-.*)?$/u', '$1', $textos));
Para o trecho entre os dois hífens, usei [^-s]+(s+[^-s]+)*
:
[^-s]+
: uma ou mais ocorrências de qualquer coisa que não seja hífen nem espaço(s+[^-s]+)*
: zero ou mais ocorrências de "espaços, seguido de vários caracteres que não sejam hífen ou espaço"
Com isso, eu capturo o texto "Frase aleatória"
, sem o risco de pegar o segundo hífen, nem os espaços que tem antes dele (mas pegando os espaços entre as palavras). Pode parecer uma complicação extra, pois você pode pensar "por que não usar .*?
que é mais simples?". O que me leva a outro tópico: a eficiência de uma regex.
Eficiência
Apenas para efeito de comparação com a resposta do usuário @Park (que também está certa, não estou criticando, apenas comparando as soluções), a regex que sugeri é mais eficiente. O regex101.com possui uma ferramenta de debugging que é bem interessante para ver como a regex se comporta.
No caso da regex (d+s+[-]s+.*?(?=s+-)|d+s+[-].*)
, veja que ela leva entre 67 e 137 passos (dependendo da string) para encontrar um match. Já a regex que sugeri leva no máximo 21 passos. A segunda versão, com s+
em vez de espaço, leva no máximo 29 passos.
E caso a string não corresponda à regex, a que eu usei demora menos para perceber isso e reportar um no-match (53 passos contra 149 - a segunda versão, com s+
, também precisa de 53 passos).
Dito isso, obviamente estes resultados são estimativas e os números exatos dependem de como a engine interna do PHP é implementada: tanto os links do regex101.com que coloquei acima quanto as funções preg_xxx
usam uma engine PCRE (Perl Compatible Regular Expressions), mas dependendo da regex e das strings utilizadas, algumas linguagens fazem otimizações internas em alguns casos, por exemplo. Mesmo usando o mesmo tipo de regex (PCRE), os números podem variar de uma linguagem/engine/ferramenta para outra.
Mas de qualquer forma os números reais não devem mudar muito. A regex da outra resposta usa alternância (|
) (o que sempre faz ela tentar todas as alternativas, até uma dar certo) e .*?
, que faz a engine testar várias possibilidades (afinal, significa "zero ou mais ocorrências de qualquer caractere"), e isso faz com que ela execute vários passos adicionais (no caso de strings que não satisfazem a regex, ela precisa testar todas as possibilidades até ter certeza de que não dá mesmo).
A minha regex até usa .*
, mas é no final da string e dentro de um bloco opcional, o que reduz um pouco este overhead, além de não ter alternância (uma única alternativa a se testar em vez de duas) e usar [^-]
(qualquer caractere que não seja hífen), que gera menos possibilidades do que o .
(que é "qualquer caractere", o que aumenta exponencialmente as possibilidades, já que o próprio hífen pode ser incluído se a regex achar necessário).
O fato de eu ter usado ^
e $
também ajuda nesse sentido, pois sem eles a regex é testada novamente a cada posição da string, até encontrar o ponto em que ela é satisfeita. Usando ^
elimina esses passos a mais, pois ela já sabe que deve sempre buscar do início da string. Ou seja, vários detalhes que isoladamente parecem "bobos", mas juntos fazem diferença.
É claro que para uma quantidade pequena de strings curtas, a diferença será insignificante (provavelmente será de milissegundos ou até menos), mas se for lidar com uma grande quantidade de dados, pode ser que faça diferença. Inclusive, usar .*
pode causar um aumento exponencial de passos, dependendo do caso (aumentar 3 caracteres na string inválida, por exemplo, só adiciona mais 3 passos na minha regex (de 53 para 56, inclusive na segunda versão com s+
), enquanto na outra adiciona 15 (pula de 149 para 164)).
Não sei se você vai lidar com uma quantidade tão grande de dados a ponto de fazer alguma diferença no desempenho, mas de qualquer forma fica registrada a alternativa.
1
Vc sempre me surpreendendo com regex. Daria mais de um upvote se fosse possível! Kk
– LipESprY
9/03 às 19:25
comentar |
Você pode usar a função preg_replace
para fazer a substituição.
A regex pode ser algo como ^w+ (d+ -[^-]+)( -.*)?$
:
- os marcadores
^
e$
são, respectivamente, o início e fim da string. Isso garante que estou verificando toda a string. - o atalho
w
significa "letras (de A a Z, maiúsculas ou minúsculas), números (de 0 a 9) ou o caractere_
" - o atalho
d
significa "qualquer dígito de 0 a 9" - o quantificador
+
significa "uma ou mais ocorrências". [^-]
é "qualquer caractere que não seja hífen".*
é "zero ou mais ocorrências de qualquer caractere", e o?
logo depois torna o trecho( -.*)
opcional (ou seja, pode ter um espaço, hífen e "qualquer coisa" no final da string)
Então a regex começa com w+
(uma ou mais ocorrências de letras, números ou _
), seguido de espaço, depois um ou mais números (d+
), espaço, hífen, vários caracteres que não são hífen (isso garante que só vai pegar até o próximo hífen), seguidos opcionalmente por espaço, hífen e .*
(zero ou mais ocorrências de qualquer coisa), e por fim o final da string.
O trecho d+ -[^-]+
está entre parênteses, e isso forma um grupo de captura. Isso quer dizer que o texto que corresponde a este trecho pode ser referenciado posteriormente.
No caso, como é o primeiro par de parênteses, o texto que for capturado estará disponível na variável especial $1
, que posso usar no segundo parâmetro do preg_replace
:
$textos = array(
"Opcao 01 - Frase aleatória - Menu Superior",
"Opcao 02 - Outra Frase aleatória - Menu Su",
"Opcao 03 - Mais 01 Frase - Menu",
"Opcao 04 - Mais Frase -",
"Opcao 05 - Frase Simples");
foreach($textos as $texto)
echo preg_replace('/^w+ (d+ -[^-]+)( -.*)?$/', '$1', $texto), PHP_EOL;
O resultado é:
01 - Frase aleatória
02 - Outra Frase aleatória
03 - Mais 01 Frase
04 - Mais Frase
05 - Frase Simples
Se quiser, pode passar o array inteiro para preg_replace
, que o retorno será outro array com as substituições feitas:
$textos = array(
"Opcao 01 - Frase aleatória - Menu Superior",
"Opcao 02 - Outra Frase aleatória - Menu Su",
"Opcao 03 - Mais 01 Frase - Menu",
"Opcao 04 - Mais Frase -",
"Opcao 05 - Frase Simples");
var_dump(preg_replace('/^w+ (d+ -[^-]+)( -.*)?$/', '$1', $textos));
Saída:
array(5)
[0]=>
string(21) "01 - Frase aleatória"
[1]=>
string(27) "02 - Outra Frase aleatória"
[2]=>
string(18) "03 - Mais 01 Frase"
[3]=>
string(15) "04 - Mais Frase"
[4]=>
string(18) "05 - Frase Simples"
Caracteres acentuados
Na regex acima, w
não considera caracteres acentuados, então se a string começar com "Opção", por exemplo, não funcionará. Outro detalhe é que w
também considera números e o caractere _
. Se quiser somente letras, uma opção é usar as propriedades Unicode (usando a categoria L
- que considera todas as letras, inclusive de outros alfabetos, como o japonês, coreano, cirílico, etc), não esquecendo de usar o modificador u
(logo depois da segunda /
na regex):
// trocar w por pL e adicionar a opção "u" na regex, para considerar letras acentuadas
var_dump(preg_replace('/^pL+ (d+ -[^-]+)( -.*)?$/u', '$1', $textos));
Se quiser deixar o w
, basta adicionar a opção u
(lembrando que o w
também considera números e o _
):
var_dump(preg_replace('/^w+ (d+ -[^-]+)( -.*)?$/u', '$1', $textos));
Espaços
As opções acima funcionam para quando há apenas um espaço separando as palavras, números e hífens.
Mas caso haja mais de um espaço separando essas partes, pode usar s+
(um ou mais espaços). Além disso, modifiquei um pouco a regex para o caso de ter mais de um espaço antes do segundo hífen (por exemplo, "Opção 01 - Frase aleatória - Menu Superior"
):
var_dump(preg_replace('/^w+s+(d+s+-s+([^-s]+(s+[^-s]+)*))(s+-.*)?$/u', '$1', $textos));
Para o trecho entre os dois hífens, usei [^-s]+(s+[^-s]+)*
:
[^-s]+
: uma ou mais ocorrências de qualquer coisa que não seja hífen nem espaço(s+[^-s]+)*
: zero ou mais ocorrências de "espaços, seguido de vários caracteres que não sejam hífen ou espaço"
Com isso, eu capturo o texto "Frase aleatória"
, sem o risco de pegar o segundo hífen, nem os espaços que tem antes dele (mas pegando os espaços entre as palavras). Pode parecer uma complicação extra, pois você pode pensar "por que não usar .*?
que é mais simples?". O que me leva a outro tópico: a eficiência de uma regex.
Eficiência
Apenas para efeito de comparação com a resposta do usuário @Park (que também está certa, não estou criticando, apenas comparando as soluções), a regex que sugeri é mais eficiente. O regex101.com possui uma ferramenta de debugging que é bem interessante para ver como a regex se comporta.
No caso da regex (d+s+[-]s+.*?(?=s+-)|d+s+[-].*)
, veja que ela leva entre 67 e 137 passos (dependendo da string) para encontrar um match. Já a regex que sugeri leva no máximo 21 passos. A segunda versão, com s+
em vez de espaço, leva no máximo 29 passos.
E caso a string não corresponda à regex, a que eu usei demora menos para perceber isso e reportar um no-match (53 passos contra 149 - a segunda versão, com s+
, também precisa de 53 passos).
Dito isso, obviamente estes resultados são estimativas e os números exatos dependem de como a engine interna do PHP é implementada: tanto os links do regex101.com que coloquei acima quanto as funções preg_xxx
usam uma engine PCRE (Perl Compatible Regular Expressions), mas dependendo da regex e das strings utilizadas, algumas linguagens fazem otimizações internas em alguns casos, por exemplo. Mesmo usando o mesmo tipo de regex (PCRE), os números podem variar de uma linguagem/engine/ferramenta para outra.
Mas de qualquer forma os números reais não devem mudar muito. A regex da outra resposta usa alternância (|
) (o que sempre faz ela tentar todas as alternativas, até uma dar certo) e .*?
, que faz a engine testar várias possibilidades (afinal, significa "zero ou mais ocorrências de qualquer caractere"), e isso faz com que ela execute vários passos adicionais (no caso de strings que não satisfazem a regex, ela precisa testar todas as possibilidades até ter certeza de que não dá mesmo).
A minha regex até usa .*
, mas é no final da string e dentro de um bloco opcional, o que reduz um pouco este overhead, além de não ter alternância (uma única alternativa a se testar em vez de duas) e usar [^-]
(qualquer caractere que não seja hífen), que gera menos possibilidades do que o .
(que é "qualquer caractere", o que aumenta exponencialmente as possibilidades, já que o próprio hífen pode ser incluído se a regex achar necessário).
O fato de eu ter usado ^
e $
também ajuda nesse sentido, pois sem eles a regex é testada novamente a cada posição da string, até encontrar o ponto em que ela é satisfeita. Usando ^
elimina esses passos a mais, pois ela já sabe que deve sempre buscar do início da string. Ou seja, vários detalhes que isoladamente parecem "bobos", mas juntos fazem diferença.
É claro que para uma quantidade pequena de strings curtas, a diferença será insignificante (provavelmente será de milissegundos ou até menos), mas se for lidar com uma grande quantidade de dados, pode ser que faça diferença. Inclusive, usar .*
pode causar um aumento exponencial de passos, dependendo do caso (aumentar 3 caracteres na string inválida, por exemplo, só adiciona mais 3 passos na minha regex (de 53 para 56, inclusive na segunda versão com s+
), enquanto na outra adiciona 15 (pula de 149 para 164)).
Não sei se você vai lidar com uma quantidade tão grande de dados a ponto de fazer alguma diferença no desempenho, mas de qualquer forma fica registrada a alternativa.
1
Vc sempre me surpreendendo com regex. Daria mais de um upvote se fosse possível! Kk
– LipESprY
9/03 às 19:25
comentar |
Você pode usar a função preg_replace
para fazer a substituição.
A regex pode ser algo como ^w+ (d+ -[^-]+)( -.*)?$
:
- os marcadores
^
e$
são, respectivamente, o início e fim da string. Isso garante que estou verificando toda a string. - o atalho
w
significa "letras (de A a Z, maiúsculas ou minúsculas), números (de 0 a 9) ou o caractere_
" - o atalho
d
significa "qualquer dígito de 0 a 9" - o quantificador
+
significa "uma ou mais ocorrências". [^-]
é "qualquer caractere que não seja hífen".*
é "zero ou mais ocorrências de qualquer caractere", e o?
logo depois torna o trecho( -.*)
opcional (ou seja, pode ter um espaço, hífen e "qualquer coisa" no final da string)
Então a regex começa com w+
(uma ou mais ocorrências de letras, números ou _
), seguido de espaço, depois um ou mais números (d+
), espaço, hífen, vários caracteres que não são hífen (isso garante que só vai pegar até o próximo hífen), seguidos opcionalmente por espaço, hífen e .*
(zero ou mais ocorrências de qualquer coisa), e por fim o final da string.
O trecho d+ -[^-]+
está entre parênteses, e isso forma um grupo de captura. Isso quer dizer que o texto que corresponde a este trecho pode ser referenciado posteriormente.
No caso, como é o primeiro par de parênteses, o texto que for capturado estará disponível na variável especial $1
, que posso usar no segundo parâmetro do preg_replace
:
$textos = array(
"Opcao 01 - Frase aleatória - Menu Superior",
"Opcao 02 - Outra Frase aleatória - Menu Su",
"Opcao 03 - Mais 01 Frase - Menu",
"Opcao 04 - Mais Frase -",
"Opcao 05 - Frase Simples");
foreach($textos as $texto)
echo preg_replace('/^w+ (d+ -[^-]+)( -.*)?$/', '$1', $texto), PHP_EOL;
O resultado é:
01 - Frase aleatória
02 - Outra Frase aleatória
03 - Mais 01 Frase
04 - Mais Frase
05 - Frase Simples
Se quiser, pode passar o array inteiro para preg_replace
, que o retorno será outro array com as substituições feitas:
$textos = array(
"Opcao 01 - Frase aleatória - Menu Superior",
"Opcao 02 - Outra Frase aleatória - Menu Su",
"Opcao 03 - Mais 01 Frase - Menu",
"Opcao 04 - Mais Frase -",
"Opcao 05 - Frase Simples");
var_dump(preg_replace('/^w+ (d+ -[^-]+)( -.*)?$/', '$1', $textos));
Saída:
array(5)
[0]=>
string(21) "01 - Frase aleatória"
[1]=>
string(27) "02 - Outra Frase aleatória"
[2]=>
string(18) "03 - Mais 01 Frase"
[3]=>
string(15) "04 - Mais Frase"
[4]=>
string(18) "05 - Frase Simples"
Caracteres acentuados
Na regex acima, w
não considera caracteres acentuados, então se a string começar com "Opção", por exemplo, não funcionará. Outro detalhe é que w
também considera números e o caractere _
. Se quiser somente letras, uma opção é usar as propriedades Unicode (usando a categoria L
- que considera todas as letras, inclusive de outros alfabetos, como o japonês, coreano, cirílico, etc), não esquecendo de usar o modificador u
(logo depois da segunda /
na regex):
// trocar w por pL e adicionar a opção "u" na regex, para considerar letras acentuadas
var_dump(preg_replace('/^pL+ (d+ -[^-]+)( -.*)?$/u', '$1', $textos));
Se quiser deixar o w
, basta adicionar a opção u
(lembrando que o w
também considera números e o _
):
var_dump(preg_replace('/^w+ (d+ -[^-]+)( -.*)?$/u', '$1', $textos));
Espaços
As opções acima funcionam para quando há apenas um espaço separando as palavras, números e hífens.
Mas caso haja mais de um espaço separando essas partes, pode usar s+
(um ou mais espaços). Além disso, modifiquei um pouco a regex para o caso de ter mais de um espaço antes do segundo hífen (por exemplo, "Opção 01 - Frase aleatória - Menu Superior"
):
var_dump(preg_replace('/^w+s+(d+s+-s+([^-s]+(s+[^-s]+)*))(s+-.*)?$/u', '$1', $textos));
Para o trecho entre os dois hífens, usei [^-s]+(s+[^-s]+)*
:
[^-s]+
: uma ou mais ocorrências de qualquer coisa que não seja hífen nem espaço(s+[^-s]+)*
: zero ou mais ocorrências de "espaços, seguido de vários caracteres que não sejam hífen ou espaço"
Com isso, eu capturo o texto "Frase aleatória"
, sem o risco de pegar o segundo hífen, nem os espaços que tem antes dele (mas pegando os espaços entre as palavras). Pode parecer uma complicação extra, pois você pode pensar "por que não usar .*?
que é mais simples?". O que me leva a outro tópico: a eficiência de uma regex.
Eficiência
Apenas para efeito de comparação com a resposta do usuário @Park (que também está certa, não estou criticando, apenas comparando as soluções), a regex que sugeri é mais eficiente. O regex101.com possui uma ferramenta de debugging que é bem interessante para ver como a regex se comporta.
No caso da regex (d+s+[-]s+.*?(?=s+-)|d+s+[-].*)
, veja que ela leva entre 67 e 137 passos (dependendo da string) para encontrar um match. Já a regex que sugeri leva no máximo 21 passos. A segunda versão, com s+
em vez de espaço, leva no máximo 29 passos.
E caso a string não corresponda à regex, a que eu usei demora menos para perceber isso e reportar um no-match (53 passos contra 149 - a segunda versão, com s+
, também precisa de 53 passos).
Dito isso, obviamente estes resultados são estimativas e os números exatos dependem de como a engine interna do PHP é implementada: tanto os links do regex101.com que coloquei acima quanto as funções preg_xxx
usam uma engine PCRE (Perl Compatible Regular Expressions), mas dependendo da regex e das strings utilizadas, algumas linguagens fazem otimizações internas em alguns casos, por exemplo. Mesmo usando o mesmo tipo de regex (PCRE), os números podem variar de uma linguagem/engine/ferramenta para outra.
Mas de qualquer forma os números reais não devem mudar muito. A regex da outra resposta usa alternância (|
) (o que sempre faz ela tentar todas as alternativas, até uma dar certo) e .*?
, que faz a engine testar várias possibilidades (afinal, significa "zero ou mais ocorrências de qualquer caractere"), e isso faz com que ela execute vários passos adicionais (no caso de strings que não satisfazem a regex, ela precisa testar todas as possibilidades até ter certeza de que não dá mesmo).
A minha regex até usa .*
, mas é no final da string e dentro de um bloco opcional, o que reduz um pouco este overhead, além de não ter alternância (uma única alternativa a se testar em vez de duas) e usar [^-]
(qualquer caractere que não seja hífen), que gera menos possibilidades do que o .
(que é "qualquer caractere", o que aumenta exponencialmente as possibilidades, já que o próprio hífen pode ser incluído se a regex achar necessário).
O fato de eu ter usado ^
e $
também ajuda nesse sentido, pois sem eles a regex é testada novamente a cada posição da string, até encontrar o ponto em que ela é satisfeita. Usando ^
elimina esses passos a mais, pois ela já sabe que deve sempre buscar do início da string. Ou seja, vários detalhes que isoladamente parecem "bobos", mas juntos fazem diferença.
É claro que para uma quantidade pequena de strings curtas, a diferença será insignificante (provavelmente será de milissegundos ou até menos), mas se for lidar com uma grande quantidade de dados, pode ser que faça diferença. Inclusive, usar .*
pode causar um aumento exponencial de passos, dependendo do caso (aumentar 3 caracteres na string inválida, por exemplo, só adiciona mais 3 passos na minha regex (de 53 para 56, inclusive na segunda versão com s+
), enquanto na outra adiciona 15 (pula de 149 para 164)).
Não sei se você vai lidar com uma quantidade tão grande de dados a ponto de fazer alguma diferença no desempenho, mas de qualquer forma fica registrada a alternativa.
Você pode usar a função preg_replace
para fazer a substituição.
A regex pode ser algo como ^w+ (d+ -[^-]+)( -.*)?$
:
- os marcadores
^
e$
são, respectivamente, o início e fim da string. Isso garante que estou verificando toda a string. - o atalho
w
significa "letras (de A a Z, maiúsculas ou minúsculas), números (de 0 a 9) ou o caractere_
" - o atalho
d
significa "qualquer dígito de 0 a 9" - o quantificador
+
significa "uma ou mais ocorrências". [^-]
é "qualquer caractere que não seja hífen".*
é "zero ou mais ocorrências de qualquer caractere", e o?
logo depois torna o trecho( -.*)
opcional (ou seja, pode ter um espaço, hífen e "qualquer coisa" no final da string)
Então a regex começa com w+
(uma ou mais ocorrências de letras, números ou _
), seguido de espaço, depois um ou mais números (d+
), espaço, hífen, vários caracteres que não são hífen (isso garante que só vai pegar até o próximo hífen), seguidos opcionalmente por espaço, hífen e .*
(zero ou mais ocorrências de qualquer coisa), e por fim o final da string.
O trecho d+ -[^-]+
está entre parênteses, e isso forma um grupo de captura. Isso quer dizer que o texto que corresponde a este trecho pode ser referenciado posteriormente.
No caso, como é o primeiro par de parênteses, o texto que for capturado estará disponível na variável especial $1
, que posso usar no segundo parâmetro do preg_replace
:
$textos = array(
"Opcao 01 - Frase aleatória - Menu Superior",
"Opcao 02 - Outra Frase aleatória - Menu Su",
"Opcao 03 - Mais 01 Frase - Menu",
"Opcao 04 - Mais Frase -",
"Opcao 05 - Frase Simples");
foreach($textos as $texto)
echo preg_replace('/^w+ (d+ -[^-]+)( -.*)?$/', '$1', $texto), PHP_EOL;
O resultado é:
01 - Frase aleatória
02 - Outra Frase aleatória
03 - Mais 01 Frase
04 - Mais Frase
05 - Frase Simples
Se quiser, pode passar o array inteiro para preg_replace
, que o retorno será outro array com as substituições feitas:
$textos = array(
"Opcao 01 - Frase aleatória - Menu Superior",
"Opcao 02 - Outra Frase aleatória - Menu Su",
"Opcao 03 - Mais 01 Frase - Menu",
"Opcao 04 - Mais Frase -",
"Opcao 05 - Frase Simples");
var_dump(preg_replace('/^w+ (d+ -[^-]+)( -.*)?$/', '$1', $textos));
Saída:
array(5)
[0]=>
string(21) "01 - Frase aleatória"
[1]=>
string(27) "02 - Outra Frase aleatória"
[2]=>
string(18) "03 - Mais 01 Frase"
[3]=>
string(15) "04 - Mais Frase"
[4]=>
string(18) "05 - Frase Simples"
Caracteres acentuados
Na regex acima, w
não considera caracteres acentuados, então se a string começar com "Opção", por exemplo, não funcionará. Outro detalhe é que w
também considera números e o caractere _
. Se quiser somente letras, uma opção é usar as propriedades Unicode (usando a categoria L
- que considera todas as letras, inclusive de outros alfabetos, como o japonês, coreano, cirílico, etc), não esquecendo de usar o modificador u
(logo depois da segunda /
na regex):
// trocar w por pL e adicionar a opção "u" na regex, para considerar letras acentuadas
var_dump(preg_replace('/^pL+ (d+ -[^-]+)( -.*)?$/u', '$1', $textos));
Se quiser deixar o w
, basta adicionar a opção u
(lembrando que o w
também considera números e o _
):
var_dump(preg_replace('/^w+ (d+ -[^-]+)( -.*)?$/u', '$1', $textos));
Espaços
As opções acima funcionam para quando há apenas um espaço separando as palavras, números e hífens.
Mas caso haja mais de um espaço separando essas partes, pode usar s+
(um ou mais espaços). Além disso, modifiquei um pouco a regex para o caso de ter mais de um espaço antes do segundo hífen (por exemplo, "Opção 01 - Frase aleatória - Menu Superior"
):
var_dump(preg_replace('/^w+s+(d+s+-s+([^-s]+(s+[^-s]+)*))(s+-.*)?$/u', '$1', $textos));
Para o trecho entre os dois hífens, usei [^-s]+(s+[^-s]+)*
:
[^-s]+
: uma ou mais ocorrências de qualquer coisa que não seja hífen nem espaço(s+[^-s]+)*
: zero ou mais ocorrências de "espaços, seguido de vários caracteres que não sejam hífen ou espaço"
Com isso, eu capturo o texto "Frase aleatória"
, sem o risco de pegar o segundo hífen, nem os espaços que tem antes dele (mas pegando os espaços entre as palavras). Pode parecer uma complicação extra, pois você pode pensar "por que não usar .*?
que é mais simples?". O que me leva a outro tópico: a eficiência de uma regex.
Eficiência
Apenas para efeito de comparação com a resposta do usuário @Park (que também está certa, não estou criticando, apenas comparando as soluções), a regex que sugeri é mais eficiente. O regex101.com possui uma ferramenta de debugging que é bem interessante para ver como a regex se comporta.
No caso da regex (d+s+[-]s+.*?(?=s+-)|d+s+[-].*)
, veja que ela leva entre 67 e 137 passos (dependendo da string) para encontrar um match. Já a regex que sugeri leva no máximo 21 passos. A segunda versão, com s+
em vez de espaço, leva no máximo 29 passos.
E caso a string não corresponda à regex, a que eu usei demora menos para perceber isso e reportar um no-match (53 passos contra 149 - a segunda versão, com s+
, também precisa de 53 passos).
Dito isso, obviamente estes resultados são estimativas e os números exatos dependem de como a engine interna do PHP é implementada: tanto os links do regex101.com que coloquei acima quanto as funções preg_xxx
usam uma engine PCRE (Perl Compatible Regular Expressions), mas dependendo da regex e das strings utilizadas, algumas linguagens fazem otimizações internas em alguns casos, por exemplo. Mesmo usando o mesmo tipo de regex (PCRE), os números podem variar de uma linguagem/engine/ferramenta para outra.
Mas de qualquer forma os números reais não devem mudar muito. A regex da outra resposta usa alternância (|
) (o que sempre faz ela tentar todas as alternativas, até uma dar certo) e .*?
, que faz a engine testar várias possibilidades (afinal, significa "zero ou mais ocorrências de qualquer caractere"), e isso faz com que ela execute vários passos adicionais (no caso de strings que não satisfazem a regex, ela precisa testar todas as possibilidades até ter certeza de que não dá mesmo).
A minha regex até usa .*
, mas é no final da string e dentro de um bloco opcional, o que reduz um pouco este overhead, além de não ter alternância (uma única alternativa a se testar em vez de duas) e usar [^-]
(qualquer caractere que não seja hífen), que gera menos possibilidades do que o .
(que é "qualquer caractere", o que aumenta exponencialmente as possibilidades, já que o próprio hífen pode ser incluído se a regex achar necessário).
O fato de eu ter usado ^
e $
também ajuda nesse sentido, pois sem eles a regex é testada novamente a cada posição da string, até encontrar o ponto em que ela é satisfeita. Usando ^
elimina esses passos a mais, pois ela já sabe que deve sempre buscar do início da string. Ou seja, vários detalhes que isoladamente parecem "bobos", mas juntos fazem diferença.
É claro que para uma quantidade pequena de strings curtas, a diferença será insignificante (provavelmente será de milissegundos ou até menos), mas se for lidar com uma grande quantidade de dados, pode ser que faça diferença. Inclusive, usar .*
pode causar um aumento exponencial de passos, dependendo do caso (aumentar 3 caracteres na string inválida, por exemplo, só adiciona mais 3 passos na minha regex (de 53 para 56, inclusive na segunda versão com s+
), enquanto na outra adiciona 15 (pula de 149 para 164)).
Não sei se você vai lidar com uma quantidade tão grande de dados a ponto de fazer alguma diferença no desempenho, mas de qualquer forma fica registrada a alternativa.
editada 11/03 às 11:57
respondida 9/03 às 1:22
hkotsubohkotsubo
11mil72253
11mil72253
1
Vc sempre me surpreendendo com regex. Daria mais de um upvote se fosse possível! Kk
– LipESprY
9/03 às 19:25
comentar |
1
Vc sempre me surpreendendo com regex. Daria mais de um upvote se fosse possível! Kk
– LipESprY
9/03 às 19:25
1
1
Vc sempre me surpreendendo com regex. Daria mais de um upvote se fosse possível! Kk
– LipESprY
9/03 às 19:25
Vc sempre me surpreendendo com regex. Daria mais de um upvote se fosse possível! Kk
– LipESprY
9/03 às 19:25
comentar |
Você precisa usar a função chamada str_replace, fiz um exemplo pra você
<?php
function limpar_stringl($string) // replace para limpar variaveis Opcao 01 - Item 01 - Menu Superior
$string = str_replace('Opcao','', $string);
$string = str_replace(' - Menu Superior','', $string);
return $string;
echo limpar_stringl("Opcao 01 - Item 01 - Menu Superior");
- Sempre que quiser refatorar um novo caractere ou conjunto de caracteres palavras etc você vai precisar adicionar uma nova linha no codigo
- Relacionar o item
$string = str_replace('caractere ou palavra','', $string);
Eu preciso como disse fazer com o REGEX. Obrigado
– Joao Nivaldo
9/03 às 1:11
comentar |
Você precisa usar a função chamada str_replace, fiz um exemplo pra você
<?php
function limpar_stringl($string) // replace para limpar variaveis Opcao 01 - Item 01 - Menu Superior
$string = str_replace('Opcao','', $string);
$string = str_replace(' - Menu Superior','', $string);
return $string;
echo limpar_stringl("Opcao 01 - Item 01 - Menu Superior");
- Sempre que quiser refatorar um novo caractere ou conjunto de caracteres palavras etc você vai precisar adicionar uma nova linha no codigo
- Relacionar o item
$string = str_replace('caractere ou palavra','', $string);
Eu preciso como disse fazer com o REGEX. Obrigado
– Joao Nivaldo
9/03 às 1:11
comentar |
Você precisa usar a função chamada str_replace, fiz um exemplo pra você
<?php
function limpar_stringl($string) // replace para limpar variaveis Opcao 01 - Item 01 - Menu Superior
$string = str_replace('Opcao','', $string);
$string = str_replace(' - Menu Superior','', $string);
return $string;
echo limpar_stringl("Opcao 01 - Item 01 - Menu Superior");
- Sempre que quiser refatorar um novo caractere ou conjunto de caracteres palavras etc você vai precisar adicionar uma nova linha no codigo
- Relacionar o item
$string = str_replace('caractere ou palavra','', $string);
Você precisa usar a função chamada str_replace, fiz um exemplo pra você
<?php
function limpar_stringl($string) // replace para limpar variaveis Opcao 01 - Item 01 - Menu Superior
$string = str_replace('Opcao','', $string);
$string = str_replace(' - Menu Superior','', $string);
return $string;
echo limpar_stringl("Opcao 01 - Item 01 - Menu Superior");
- Sempre que quiser refatorar um novo caractere ou conjunto de caracteres palavras etc você vai precisar adicionar uma nova linha no codigo
- Relacionar o item
$string = str_replace('caractere ou palavra','', $string);
respondida 9/03 às 1:06
Martins LuanMartins Luan
1207
1207
Eu preciso como disse fazer com o REGEX. Obrigado
– Joao Nivaldo
9/03 às 1:11
comentar |
Eu preciso como disse fazer com o REGEX. Obrigado
– Joao Nivaldo
9/03 às 1:11
Eu preciso como disse fazer com o REGEX. Obrigado
– Joao Nivaldo
9/03 às 1:11
Eu preciso como disse fazer com o REGEX. Obrigado
– Joao Nivaldo
9/03 às 1:11
comentar |
Obrigado por contribuir com o Stack Overflow em Português!
- Certifique-se de responder à pergunta. Entre em detalhes sobre a sua solução e compartilhe o que você descobriu.
Mas evite …
- Pedir esclarecimentos ou detalhes sobre outras respostas.
- Fazer afirmações baseadas apenas na sua opinião; aponte referências ou experiências anteriores.
Para aprender mais, veja nossas dicas sobre como escrever boas respostas.
Registre-se ou faça log-in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Registre-se usando o Google
Registre-se usando o Facebook
Registre-se usando Email e Senha
Publicar como convidado
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fpt.stackoverflow.com%2fquestions%2f367165%2flimpar-string-com-regex%23new-answer', 'question_page');
);
Publicar como convidado
Required, but never shown
Registre-se ou faça log-in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Registre-se usando o Google
Registre-se usando o Facebook
Registre-se usando Email e Senha
Publicar como convidado
Required, but never shown
Registre-se ou faça log-in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Registre-se usando o Google
Registre-se usando o Facebook
Registre-se usando Email e Senha
Publicar como convidado
Required, but never shown
Registre-se ou faça log-in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Registre-se usando o Google
Registre-se usando o Facebook
Registre-se usando Email e Senha
Registre-se usando o Google
Registre-se usando o Facebook
Registre-se usando Email e Senha
Publicar como convidado
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Já tentou isso sem aspas? "d+s+[-]s+w+s+d+"
– Park
9/03 às 0:44
Qual linguagem? você já tem algum contexto de codigo que não tem funcionado?
– Martins Luan
9/03 às 0:50
@Park olha eu acabei de tentar e não deu certo. Não traz nada de resposta. Até o w deu certo mas depois ja da erro. Obrigado
– Joao Nivaldo
9/03 às 0:57
@MartinsLuan vou usar no PHP.
– Joao Nivaldo
9/03 às 0:57
1
@hkotsubo feito amigo. Acho que melhorou agora. Obrigado pela dica.
– Joao Nivaldo
9/03 às 1:12