Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Tiago Souza Ribeiro

[Resolvido]  sugestões para otimizar função

Recommended Posts

Olá. Eu andei um tempo procurando algum método de verificar a presença de caracteres em uma string, mas nenhum era como eu queria, então fiz uma função mais simples e que satisfaz minhas necessidades. Porém ela faz loops, e de tanto ver gente com maus olhos para eles, acho que a função não ficou tão boa assim...

Segue o código fonte:

function contain($chars, $string, $all = false) {
$contain = false; // Armazena o retorno da função
switch($all) {
	case true: // Caso seja obrigatória a presença de todos caracteres...
		$occur_num = 0; // Número de ocorrências (sem repetir) de cada caractere
		for($i = 0; $i < strlen($chars); $i++) {
			if(strpos($string, $chars[$i]) !== false) // Verifica se contém o caracter na string
				$occur_num++; // Caso contenha, incrementa o contador de ocorrências em 1
		}
		if($occur_num == strlen($chars)) // Verifica se o número de ocorrências é igual o número de caracteres passados para verificar
			$contain = true; // Se for igual, a função retorna true (todos caracteres estão presentes na string)
	break;
	default: // Caso não seja obrigatória a presença de todos caracteres...
		for($i = 0; $i < strlen($chars); $i++) {
			if(strpos($string, $chars[$i]) !== false) // Verifica se contém o caracter na string
				$contain = true; // Caso contenha, a função retorna true (ao menos um caractere está presente)
		}
	break;
}
return $contain;
}

// Exemplo de uso:
$email = "root@root-servers.net";
contain("@.", $email, true); // TRUE

 

Então... o Andrey sempre faz uma versão melhor e funcional dos códigos que mostro pra ele, então provavelmente esse aí dá pra melhorar também, hehe. Por enquanto estou tentando aqui fazer parar o loop imediatamente quando a função puder retornar true, evitando loops desnecessários. Se alguém tiver uma sugestão, agradeço :D

 

Até mais ^^

Compartilhar este post


Link para o post
Compartilhar em outros sites

Cara você quer ver se existe um determinado caractere em uma string se for faça isso:

$ver = strstr($email, '@');
if($ver){
echo "Tem um @ no email ";
}

 

:X

Compartilhar este post


Link para o post
Compartilhar em outros sites

Obrigado por responder.

 

Mas e se eu quiser verificar de duas maneiras diferentes?

- Se algum dos caracteres está presente

- Se todos caracteres estão presentes

 

Então o que muda nessa função minha é apenas trocar strpos por strstr, o restante vai ser igual '-'

 

Ah, só uma pergunta simples aqui (não merece um tópico): para fazer duas validações ou mais na segunda expressão do for usa o && (ou and) igual no if e outros, ou separa com uma vírgula? A divisão de parâmetros do for é estranha :s

Ex:

for($num = 0; $num > 5 && $num < 10; $num++)

Compartilhar este post


Link para o post
Compartilhar em outros sites

Existe varias formas de verificar

 

strstr

 

str_pos

 

strrpos

 

substr_count // Se você quiser quantas vezes uma string aparece na frase

 

verifica qual melhor lhe atende

Compartilhar este post


Link para o post
Compartilhar em outros sites

for($num = 0; $num > 5 && $num < 10; $num++) 

???? :huh:

 

:seta:

for($num = 6; $num < 10; $num++)

 

Foi só um exemplo, só quero saber se tem alguma forma de usar mais de uma condição na segunda expressão, se usa vírgula para separá-las ou os operadores lógicos normalmente... Não vi falar disso no php.net.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Pensei num novo agora :

 

function conta($str, $char){

$chart = "IKILOL";

$go = substr_replace($char, $chart, $str, $count);

return $count;

}

$string = "Eu não fui para o campeonato";
$matriz = array("a", "e", "f");
conta($string, $matriz);

 

A duvida ja foi respondida mais não sei porque deu vontade de postar isso aqui, faz a mesma coisa do substr_count.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Foi só um exemplo, só quero saber se tem alguma forma de usar mais de uma condição na segunda expressão, se usa vírgula para separá-las ou os operadores lógicos normalmente... Não vi falar disso no php.net.

Sim. Você pode utilizar mais de um condicional dentro do for, entretanto, poucos os desenvolvedores sabem exatamente o que acontece dentro do for.

 

Vamos definir alguma coisas.

O for possui 3 expressões, e não parâmetros. Somente um dos

- A primeira expressão é executada antes de iniciar a primeira iteração, é executada apenas uma vez.

- A segunda expressão é verificada antes de cada iteração e só, e somente só, se for true, a iteração ocorrerá.

- A terceira expressão é realizada no final de cada iteração.

 

Se você for ver bem, um for é a forma "padronizada" de gerar o código abaixo:

$i = 0;//Primeira expressão, executada antes do início da iteração
while($i < 10) { //Segunda expressão, executada antes do início de cada iteração
  /** ....código...... **/

  $i++;//Terceira expressão, executada no término de cada iteração
}

 

Todos os 3 parâmetros são opcionais. Entretanto, o segundo é o mais importante, pois é o condicional de iteração.

Fazer isso:

for(; ; ){}

É o mesmo que:

while(true){}

Dependendo do contexto, é bem útil.

 

Sim, você pode usar mais operadores dentro de uma expressão. O exemplo 4 do php.net mostra isso:

/* example 4 */
for ($i = 1, $j = 0; $i <= 10; $j += $i, print $i, $i++);

Compartilhar este post


Link para o post
Compartilhar em outros sites

Sim, você pode usar mais operadores dentro de uma expressão. O exemplo 4 do php.net mostra isso:

/* example 4 */
for ($i = 1, $j = 0; $i <= 10; $j += $i, print $i, $i++);

Ah, então é certo fazer isso aqui né?

 

for($i = 0; $i <= 5 && valida($x); $i++)

Compartilhar este post


Link para o post
Compartilhar em outros sites

Operadores lógicos (AND, OR, NOT, XOR).

Compartilhar este post


Link para o post
Compartilhar em outros sites

Ah, então é certo fazer isso aqui né?

 

for($i = 0; $i <= 5 && valida($x); $i++)

 

Sim, funciona.

 

Voltando ao assunto do tópico, tenho alguns apontamentos a fazer:

 

- Se já houver um padrão, procure seguí-lo.

 

Veja que a maioria das funções de string do PHP usam como ordem de parâmetros $haystack (palheiro), $needle (agulha).

http://br2.php.net/manual/pt_BR/function.strstr.php

http://br2.php.net/manual/pt_BR/function.stristr.php

http://br2.php.net/manual/pt_BR/function.strpos.php

http://br2.php.net/manual/pt_BR/function.strrchr.php

http://br2.php.net/manual/pt_BR/function.substr.php

 

Ou seja, a string que será operada vem primeiro, o argumento de operação vem depois

 

function contains($haystack, $needle, $all = false)

 

- Se você vai definir o valor de apenas uma variável, em consequência de uma condicional, você pode usar o teste como valor da variável:

 

if ($occur_num == strlen($chars))
   $contain = true;

 

$contain = $occur_num == strlen($chars);

 

- Procure aplicar uma técnica denominada early return. Consiste em você sair de uma função/laço o mais rápido possível. Observe que na sua função, você opera um switch, guarda o resultado, não faz mais nada e, no fim, retorna o resultado. Você pode retorná-lo diretamente do ponto onde é relevante:

 

switch ($all) {
   case true:
       ...
       $contain = $occur_num == strlen($chars);
       break;
   default:
       ...
           if (false !== strpos($string, $chars[i])) {
               $contain = true;
       ...
}
return $contain;

 

switch ($all) {
   case true:
       ...
       return $occur_num == strlen($chars);
   default:
       ...
           if (false !== strpos($string, $chars[i])) {
               return true;
       ...
}

 

De todo modo, o que você precisa não é de tão grande complexidade, veja:

function contains($haystack, $needle, $all = false)
{
   if (!is_array($needle)) {
       $needle = str_split($needle);
   }
   $stopOn = !$all;
   foreach ($needle as $x) {
       if ($stopOn === strpos($haystack, $x) {
           return $stopOn;
       }
   }
   return $all;
}

 

- $stopOn armazena o critério de parada:

-- Quando procuramos por qualquer uma podemos encerrar na primeira ocorrência de true

-- Quando procuramos por todas, a função deve falhar na primeira ocorrência de false

 

Segundo essa lógica, $stopOn armazena exatamente o valor contrário de $all

 

Iteramos entre cada caractere recebido aplicando o critério de parada.

 

Veja return early sendo aplicada dentro do foreach>if.

 

Eu não preciso guardar dentro de uma variável $retorno e enviar só no final de todas as iterações.

 

Encontrei o que eu preciso, retorno dali mesmo e a função termina o seu trabalho.

 

Como $all e $stopOn são contrárias, fica simples. Quando eu não posso retornar uma, o retorno é, logicamente, a outra.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Quando postei o código do primeiro post aqui no tópico, ele era o alpha do alpha ainda, kkkk, modifiquei ele bastante, agora está usando early return (por meio de ternário pra economizar linhas :)).

 

Sobre a ordem da palha e agulha (kkkk): é esquisita essa ordem, com a função chamando contain, ao executar isso:

contain("abc", "kabum", true);

a forma textual disso seria algo como: contém abc em kabum?, mais lógico que contém em kabum abc '-'

 

Não entendi muito bem o que tu falou, e essa última função parece ter algo errado :S, mas olha como está a minha atualmente:

function contain($chars, $string, $all = false) {
if($all) {
	$occur_num = 0;
	for($i = 0; isset($chars{$i}); $i++)) {
		if(substr_count($string, $chars{$i}) >= 1)
			$occur_num++;
		else
			return false;
	}
	return ($occur_num == strlen($chars)) ? true : false;
}
else {
	for($i = 0; isset($chars{$i}); $i++)) {
		if(substr_count($string, $chars{$i}) >= 1)
			return true;
	}
}
return false;
}

Algo a melhorar? :D

Compartilhar este post


Link para o post
Compartilhar em outros sites

Não entendi muito bem o que tu falou, e essa última função parece ter algo errado :S

 

De fato. Versão corrigida:

<?php

function contains($haystack, $needle, $all = false)
{
   if (!is_array($needle)) {
       $needle = str_split($needle);
   }
   foreach ($needle as $x) {
       if ($all === (false === strpos($haystack, $x))) {
           return !$all;
       }
   }
   return $all;
}

 

Teste

 

<?php

//require "PHPUnit/Autoload.php";
require "contains.php";

class containsTest extends PHPUnit_Framework_TestCase
{
   private $string         = 'Lorem ipsum dolor sit amet consecteur';
   private $always_true    = 'aeiou'; // True em ambos os testes
   private $any_true       = 'abcde'; // True com $all = false
   private $always_false   = 'bfghj'; // False em ambos os testes

   // Testa se contains retorna true quando encontrado pelo menos um caractere
   public function testContainsAny()
   {
       $this->assertTrue(contains($this->string, $this->any_true));
   }

   // Testa se retorna false quando não encontra nada com $all = false
   public function testNotContainsAny()
   {
       $this->assertFalse(contains($this->string, $this->always_false));
   }

   // Testa se retorna true quando encontra todos os caracteres
   public function testContainsAll()
   {
       $this->assertTrue(contains($this->string, $this->always_true, true));
   }

   // Testa se retorna false quando não encontra pelo menos um caractere
   public function testNotContainsAll()
   {
       $this->assertFalse(contains($this->string, $this->any_true, true));
   }
}

 

 

 

mas olha como está a minha atualmente:

function contain($chars, $string, $all = false) {
if($all) {
	$occur_num = 0;
##		for($i = 0; isset($chars{$i}); $i++)) {
##			if(substr_count($string, $chars{$i}) >= 1)
			$occur_num++;
		else
			return false;
	}
	return ($occur_num == strlen($chars)) ? true : false;
}
else {
##		for($i = 0; isset($chars{$i}); $i++)) {
##			if(substr_count($string, $chars{$i}) >= 1)
			return true;
	}
}
return false;
}

Algo a melhorar? :D

 

Percebe que as linhas comentadas se repetem?? Podemos pensar em reusabilidade de código e tentar melhorar.

 

Veja que o uso do ternário está redundante??? Se for true, retorne true, se for false, retorne false???

 

Retorne diretamente o teste

 

return $occur_num == strlen($chars);

 

O efeito é o mesmo.

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.