JSFiddle - React, Tailwind, and code Playground

by mgibsonbr

HTML

<ul>
</ul>
<input />
<button>buscar</button>
<button>arvore</button>
<button>\xe1rvore</button>
<button>a\u0301rvore</button>
<br/>
<label><input type="checkbox" checked />Ignorar maiúsculas/minúsculas</label>
<label title="Se checado, acentos no termo de busca casam com palavras não acentuadas também. Se deixado sem, acentos no termo de busca só casam com letras igualmente acentuadas (embora as mesmas podem estar representadas de uma forma diferente)."><input type="checkbox" checked disabled />Ignorar acento no termo de busca</label>
<hr/>
Tempo de preparo: <span>&#x221e;</span> µs (só faz sentido se a lista for grande)
<br/>
Tempo médio de busca: <span>&#x221e;</span> µs (<span>0</span> casos)

CSS

.achou {
    background: lightgray;
}

JavaScript

function preparar(lista) {
    return lista.map(prepararTermoBusca);
}

function prepararTermoBusca(str) {
    str = str.replace(/[ÀÁÂÃÄÅ]/,"A");
    str = str.replace(/[àáâãäå]/,"a");
    str = str.replace(/[ÈÉÊË]/,"E");
    str = str.replace(/[Ç]/,"C");
    str = str.replace(/[ç]/,"c");

    // o resto
    str = str.replace(/[èéêë]/,"e");
    str = str.replace(/[ÌÍÎÏ]/,"I");
    str = str.replace(/[ìíîï]/,"i");
    str = str.replace(/[ÒÓÔÖÕ]/,"O");
    str = str.replace(/[òóôöõ]/,"o");
    str = str.replace(/[ÙÚÛÜ]/,"U");
    str = str.replace(/[ùúûü]/,"u");
    str = str.replace(/[Ñ]/,"N");
    str = str.replace(/[ñ]/,"n");

    return str.replace(/[^a-z0-9]/gi,''); 
}

function comparar(elementoLista, termoBusca, ignoreCase) {
    if ( ignoreCase )
        return elementoLista.toLocaleLowerCase() == termoBusca.toLocaleLowerCase();
    return elementoLista == termoBusca;
}

////// Teste //////

var lista = [
    "acentuacao",
    'arvore',
    '\xe1rvore',
    'a\u0301rvore',
    "divagacão",
    "programaçao",
    "taxação"
];
var listaPreparada = null;

for ( var i = 0 ; i < lista.length ; i++ )
    $("ul").append('<li>' + lista[i] + '</li>');

var buscas = [];

$("button:eq(0)").click(function() {
    var termoBusca = $("input:eq(0)").val();
    $("li").removeClass("achou");
    
    if ( !listaPreparada ) {
        var now = new Date();
        var repetir = 1000;
        while ( repetir-- > 0 )
            listaPreparada = preparar(lista);
        $("span:eq(0)").text(((new Date() - now)/1).toFixed(3));
    }
    
    var ignoreCase = $("input:eq(1)").prop("checked");
    
    var now = new Date();
    var repetir = 10000;
    while ( repetir-- > 0 ) {
        var termoPreparado = prepararTermoBusca(termoBusca);
        for ( var i = 0 ; i < listaPreparada.length ; i++ )
            if ( comparar(listaPreparada[i], termoPreparado, ignoreCase) )
                $("li").eq(i).addClass("achou");
    }
    buscas.push((new Date() - now)/lista.length/10);
   ...