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;








4















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?










compartilhar|melhorar esta pergunta
























  • 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

















4















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?










compartilhar|melhorar esta pergunta
























  • 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













4












4








4








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?










compartilhar|melhorar esta pergunta
















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






compartilhar|melhorar esta pergunta















compartilhar|melhorar esta pergunta













compartilhar|melhorar esta pergunta




compartilhar|melhorar esta pergunta








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

















  • 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










3 Respostas
3






ativas

mais antigas

votos


















3














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.







compartilhar|melhorar esta resposta

























  • 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


















5














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.






compartilhar|melhorar esta resposta




















  • 1





    Vc sempre me surpreendendo com regex. Daria mais de um upvote se fosse possível! Kk

    – LipESprY
    9/03 às 19:25


















-1














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");


  1. Sempre que quiser refatorar um novo caractere ou conjunto de caracteres palavras etc você vai precisar adicionar uma nova linha no codigo

  2. Relacionar o item$string = str_replace('caractere ou palavra','', $string);





compartilhar|melhorar esta resposta























  • Eu preciso como disse fazer com o REGEX. Obrigado

    – Joao Nivaldo
    9/03 às 1:11











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
);



);













rascunho salvo

rascunho descartado


















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









3














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.







compartilhar|melhorar esta resposta

























  • 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















3














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.







compartilhar|melhorar esta resposta

























  • 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













3












3








3







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.







compartilhar|melhorar esta resposta















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.








compartilhar|melhorar esta resposta














compartilhar|melhorar esta resposta



compartilhar|melhorar esta resposta








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

















  • 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













5














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.






compartilhar|melhorar esta resposta




















  • 1





    Vc sempre me surpreendendo com regex. Daria mais de um upvote se fosse possível! Kk

    – LipESprY
    9/03 às 19:25















5














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.






compartilhar|melhorar esta resposta




















  • 1





    Vc sempre me surpreendendo com regex. Daria mais de um upvote se fosse possível! Kk

    – LipESprY
    9/03 às 19:25













5












5








5







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.






compartilhar|melhorar esta resposta















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.







compartilhar|melhorar esta resposta














compartilhar|melhorar esta resposta



compartilhar|melhorar esta resposta








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












  • 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











-1














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");


  1. Sempre que quiser refatorar um novo caractere ou conjunto de caracteres palavras etc você vai precisar adicionar uma nova linha no codigo

  2. Relacionar o item$string = str_replace('caractere ou palavra','', $string);





compartilhar|melhorar esta resposta























  • Eu preciso como disse fazer com o REGEX. Obrigado

    – Joao Nivaldo
    9/03 às 1:11















-1














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");


  1. Sempre que quiser refatorar um novo caractere ou conjunto de caracteres palavras etc você vai precisar adicionar uma nova linha no codigo

  2. Relacionar o item$string = str_replace('caractere ou palavra','', $string);





compartilhar|melhorar esta resposta























  • Eu preciso como disse fazer com o REGEX. Obrigado

    – Joao Nivaldo
    9/03 às 1:11













-1












-1








-1







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");


  1. Sempre que quiser refatorar um novo caractere ou conjunto de caracteres palavras etc você vai precisar adicionar uma nova linha no codigo

  2. Relacionar o item$string = str_replace('caractere ou palavra','', $string);





compartilhar|melhorar esta resposta













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");


  1. Sempre que quiser refatorar um novo caractere ou conjunto de caracteres palavras etc você vai precisar adicionar uma nova linha no codigo

  2. Relacionar o item$string = str_replace('caractere ou palavra','', $string);






compartilhar|melhorar esta resposta












compartilhar|melhorar esta resposta



compartilhar|melhorar esta resposta










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

















  • 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

















rascunho salvo

rascunho descartado
















































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.




rascunho salvo


rascunho descartado














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





















































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







Popular posts from this blog

Can't initialize raids on a new ASUS Prime B360M-A motherboard2019 Community Moderator ElectionSimilar to RAID config yet more like mirroring solution?Can't get motherboard serial numberWhy does the BIOS entry point start with a WBINVD instruction?UEFI performance Asus Maximus V Extreme

Identity Server 4 is not redirecting to Angular app after login2019 Community Moderator ElectionIdentity Server 4 and dockerIdentityserver implicit flow unauthorized_clientIdentityServer Hybrid Flow - Access Token is null after user successful loginIdentity Server to MVC client : Page Redirect After loginLogin with Steam OpenId(oidc-client-js)Identity Server 4+.NET Core 2.0 + IdentityIdentityServer4 post-login redirect not working in Edge browserCall to IdentityServer4 generates System.NullReferenceException: Object reference not set to an instance of an objectIdentityServer4 without HTTPS not workingHow to get Authorization code from identity server without login form

2005 Ahvaz unrest Contents Background Causes Casualties Aftermath See also References Navigation menue"At Least 10 Are Killed by Bombs in Iran""Iran"Archived"Arab-Iranians in Iran to make April 15 'Day of Fury'"State of Mind, State of Order: Reactions to Ethnic Unrest in the Islamic Republic of Iran.10.1111/j.1754-9469.2008.00028.x"Iran hangs Arab separatists"Iran Overview from ArchivedConstitution of the Islamic Republic of Iran"Tehran puzzled by forged 'riots' letter""Iran and its minorities: Down in the second class""Iran: Handling Of Ahvaz Unrest Could End With Televised Confessions""Bombings Rock Iran Ahead of Election""Five die in Iran ethnic clashes""Iran: Need for restraint as anniversary of unrest in Khuzestan approaches"Archived"Iranian Sunni protesters killed in clashes with security forces"Archived