Categoria: Javascript

JavaScript: substituição em Strings

Substituir texto em Strings é algo muito comum em qualquer linguagem. Neste artigo, quero analisar qual seria a forma mais eficiente de fazer isso em JavaScript.

Dada a seguinte frase numa String:

var frase = "O céu está azul hoje!";

Qual é a melhor forma de trocarmos a cor do céu na frase acima para “verde”?

“O céu está verde hoje!”

Métodos de substituição

Após algumas pesquisas cheguei a quatro variações das técnicas para substituição de Strings. Elas fazem substituição de todas as ocorrências da String a ser substituída, caso haja mais de uma.

Criando uma expressão regular com RegExp

var regex = new RegExp("azul", "g");
var resultado = frase.replace(regex, "verde");

O RegExp é um tipo de objeto que recebe como parâmetro em seu construtor uma expressão regular e um modificador. A expressão usada foi a mais simples possível (“azul”). O modificador "g" significa global, isto é, a expressão irá afetar todas as ocorrências na frase, caso contrário, somente a primeira seria localizada.

Após criar a expressão regular, usei-a no método replace() da String. O primeiro argumento é a expressão usada para localizar partes do texto, as quais serão substituídas pelo conteúdo do segundo argumento (“verde”).

Criando uma expressão regular “nativa”

var regex  = /azul/g;
var resultado = frase.replace(regex, "verde");

Este código faz o mesmo que o anterior, mas escrevendo a expressão regular diretamente no código.

Usando as funções split e join

var resultado = frase.split('azul').join('verde');

Explicando o código acima, a função split() da String divide nossa frase em duas partes: uma com o conteúdo anterior da palavra “azul” e outra com o conteúdo posterior. O resultado é o vetor ["O céu está ", " hoje!"]. Depois disso, a função join() do array une os itens do vetor separando-os pela palavra “verde”.

Usando a função indexOf e substring

var pos = frase.indexOf('azul');
var ultpos = 0;
var resultado = '';
while (pos >= 0) {
    resultado += frase.substring(ultpos, pos) + 'verde';
    ultpos = pos + 4;
    pos = frase.indexOf('azul', pos + 4);
}
if (ultpos < frase.length) {
    resultado += frase.substring(ultpos, frase.length);
}

O código acima procura pela ocorrência da palavra “azul” na nossa frase e, enquanto houver alguma, vai montando uma outra String com a palavra substituída.

Fazendo o teste de desempenho

O primeiro passo para analisar a eficiência das soluções foi utilizar Jsperf. Este site permite a criação de casos de teste comparativos, com quantas variações forem necessárias. Eles podem ser executados por qualquer usuário, em qualquer navegador.

Clique aqui para ver ou executar os testes no jsperf!

Alguns testes foram realizados e o gráfico na data em que escrevo o artigo é o seguinte:

string-replace-performance

Nota: o item “regex2” se refere à expressão regular “nativa” mencionada anteriormente.

Cada novo usuário que executar os testes irá contribuir para a análise, então é provável que logo o gráfico no site Jsperf esteja diferente.

Análise dos resultados

Não temos uma conclusão! Não existe um consenso sobre o método mais rápido!

Em resumo:

  • O método com regex foi o melhor nas versões 7 e 10 do Internet Explorer
  • O método com split e join ganha no Google Chrome
  • E o método com indexOf e substring venceu no Firefox e no Ópera

Minha sugestão, baseada numa análise geral, é usar expressões regulares “nativas”, isto é, sem o RegExp. Note como a barra laranja está sempre em primeiro ou segundo lugar.


Este artigo foi baseado na minha resposta no StackOverflow em Português!

Entenda como Zebrar uma tabela com CSS

Colorir alternadamente as linhas de uma tabela é um requisito comum. A abordagem mais comum é usar um código personalizado na view para adicionar estilos alternados. No entanto, é possível fazer isso sem o uso de uma linguagem de back-end como Java, PHP ou .Net.

CSS 3

Podemos usar estilos CSS selecionando os elementos pares e ímpares, como no seguinte exemplo:

/* linhas pares (even) */
.tabela tbody tr:nth-child(even) {
    background-color: #CCC;
}
/* linhas ímpares (odd) */
.tabela tbody tr:nth-child(odd) {
    background-color: #FFF;
}

Continuando com o exemplo, agora só precisamos adicionar a classe tabela ao elemento <table> no HTML:

<table class="tabela">
    <thead>
        ....
    </thead>
    <tbody>
        ....
    </tbody>
</table>

Veja um exemplo funcional no Jsfiddle!

Que bruxaria é essa?

Para quem não conhece a sintaxe do CSS, ou nem sabe que tipo de tecnologia é essa, trata-se de um tipo de linguagem para aplicar primariamente estilos visuais nos elementos de uma página web.

Considere o seguinte exemplo:

seletor {
    atributo1: valor1;
    atributo2: valor2;
}

Esta é a estrutura de uma regra (rule) do CSS. Regras são compostas pelas seguintes partes:

  • Seletor: define quais elementos serão afetados pela regra.
  • Atributo: especifica qual atributo será afetado. Podem haver vários atributos por regra.
  • Valor: o respectivo valor de cada atributo.

Um seletor que começa com um ponto (.), como em .tabela, chama-se seletor de classes. Ele diz ao navegador para aplicar a regra aos elementos que possuem o atributo class com a respectiva classe, como em class="tabela". Um elemento pode conter várias classes, cujos nomes devem ser separados por espaços em branco, como em class="tabela outra-classe".

Voltemos agora ao exemplo do tópico anterior. O seletor.tabela tbody tr:nth-child(even) primeiramente seleciona elementos que contém o atributo class="tabela".

Em seguida, encontramos o trecho tbody. Este é um seletor de tag, isto é, ele seleciona as tags <tbody>, que define o corpo da tabela, de forma que não zebramos o título da mesma. Como isso vem depois de .tabela e é separado por um espaço em branco, incluiremos todos os elementos <tbody> filhos do elemento com class="tabela". O próximo trecho é tr, que seleciona todos os elementos <tr> filhos do elemento <tbody>. Note que, se houver uma tabela dentro de outra, as linhas da tabela mais interna também serão afetadas. Se quiséssemos especificar a seleção apenas dos filhos diretos, poderíamos usar o caractere maior (>), como em .tabela > tbody > tr.

O seletor tr é seguido de um caractere de dois pontos (:). Este é um pseudo-seletor. Ele altera o seletor anterior. Nesse caso o pseudo-seletor nth-child() permite especificar quais elementos do conjunto total de tags <tr> serão realmente incluídos. Dentro do parêntesis, poderíamos especificar um índice numérico. Por exemplo, tr:nth-child(5) iria selecionar apenas a quinta linha da tabela. Porém, usamos os valores especiais odd e even para definir índices ímpares e pares, respectivamente.

Finalmente, aplicamos a cor #CCC (um cinza claro) ao atributo background-color (cor de fundo) às linhas pares. Depois, aplicamos a cor #FFF (branco, em hexadecimal) como cor de fundo das linhas ímpares. Note que o valor #FFF é uma abreviação para #FFFFFF. Na versão com 6 letras, cada dupla de bytes representam uma cor do RGB (Red, Green, Blue).

Ufa! Entendeu? 😉

Se você lê Inglês e quer se aprofundar, recomendo a referência da fundação Mozilla.

Compatibilidade com navegadores antigos

A solução em CSS é muito legal, mas o seletor nth-child não vai funcionar no Internet Explorer 6, 7 e 8. Se precisar manter a compatibilidade com essas versões do navegador, uma alternativa é usar jQuery. O jQuery simula seletores mais novos mesmo em navegadores antigos através de código Javascript.

O seguinte trecho de código aplica a coloração em linhas ímpares e pares logo após o carregamento da página:

$(document).ready(function() {
    //linhas pares, iniciando em zero
    $('.tabela tbody tr:even').css('background-color', '#FFF'); 
    //linhas ímpares iniciando em zero
    $('.tabela tbody tr:odd').css('background-color', '#CCC'); 
});

Note que inverti odd e even. Isso é porque a versão CSS do seletor usa índices baseados em 1 (1, 2, 3, …, N), enquanto a versão jQuery usa índices de vetores Javascript, que são baseados em 0 (0, 1, 2, …, N – 1).

Veja o exemplo funcional da versão em Javascript no Jsfiddle!


Este artigo foi baseado na minha resposta no StackOverflow em Português!

Creative Commons O blog State of the Art de Luiz Ricardo é licenciado sob uma Licença Creative Commons. Copie, compartihe e modifique, apenas cite a fonte.