Javascript RegExp + Limites de palavras + caracteres unicode

Estou construindo uma pesquisa e vou usar o autocomplete do javascript com ela. Eu sou da Finlândia (língua finlandesa), então eu tenho que lidar com alguns caracteres especiais como ä, ö e å

Quando o usuário digita texto no campo de input de pesquisa, tento corresponder o texto aos dados.

Aqui está um exemplo simples que não está funcionando corretamente se o usuário digitar, por exemplo, “ää”. Mesma coisa com “äl”

var title = "this is simple string with finnish word tämä on ääkköstesti älkää ihmetelkö"; // Does not work var searchterm = "äl"; // does not work //var searchterm = "ää"; // Works //var searchterm = "wi"; if ( new RegExp("\\b"+searchterm, "gi").test(title) ) { $("#result").html("Match: ("+searchterm+"): "+title); } else { $("#result").html("nothing found with term: "+searchterm); } 

http://jsfiddle.net/7TsxB/

Então, como posso obter esses caracteres ä, ö e å para trabalhar com regex javascript?

Acho que devo usar códigos unicode, mas como devo fazer isso? Os códigos para esses caracteres são: [\ u00C4, \ u00E4, \ u00C5, \ u00E5, \ u00D6, \ u00F6]

=> äÄåÅöÖ

Parece haver um problema com o Regex e a palavra boundary \b correspondendo ao início de uma string com um caractere inicial fora do intervalo normal de 256 bytes.

Em vez de usar \b , tente usar (?:^|\\s)

 var title = "this is simple string with finnish word tämä on ääkköstesti älkää ihmetelkö"; // Does not work var searchterm = "äl"; // does not work //var searchterm = "ää"; // Works //var searchterm = "wi"; if ( new RegExp("(?:^|\\s)"+searchterm, "gi").test(title) ) { $("#result").html("Match: ("+searchterm+"): "+title); } else { $("#result").html("nothing found with term: "+searchterm); } 

Demolir:

(?: parêntese () forma um grupo de captura no Regex Parêntese iniciada com um ponto de interrogação e dois pontos ?: forma um grupo sem captura. Eles apenas agrupam os termos juntos

^ o símbolo de sinal de intercalação corresponde ao começo de uma corda

| a barra é o operador “ou”.

\s corresponde a espaços em branco (aparece como \\s na string porque temos que escaping da barra invertida)

) fecha o grupo

Portanto, em vez de usar \b , que corresponde a limites de palavra e não funciona para caracteres unicode, usamos um grupo que não captura o que corresponde ao início de uma string OU espaço em branco.

A class de caractere \b em JavaScript RegEx é realmente útil apenas com codificação ASCII simples. \b é um código de atalho para o limite entre os conjuntos \w e \W ou \w e o início ou fim da cadeia. Esses conjuntos de caracteres levam em conta apenas caracteres “palavra” ASCII, onde \w é igual a [a-zA-Z0-9_] e \W é a negação dessa class.

Isso faz com que as classs de caracteres RegEx sejam inúteis para lidar com qualquer idioma real.

\s deve funcionar para o que você deseja fazer, desde que os termos de pesquisa sejam apenas delimitados por espaços em branco.

essa questão é antiga, mas acho que encontrei uma solução melhor para limite em expressões regulares com letras unicode. Usando XRegExp você pode implementar um limite \ b válido expandindo este

 XRegExp('(?=^|$|[^\\p{L}])') 

O resultado é um 4000+ char longo, mas parece funcionar bastante desempenho.

Algumas explicações: (? =) É uma lookahead de comprimento zero que procura um limite inicial ou final ou um caractere unicode sem letra. O pensamento mais importante é o lookahead, porque o \ b não captura nada: é simplesmente verdadeiro ou falso.

Eu recomendo que você use o XRegExp quando tiver que trabalhar com um conjunto específico de caracteres do Unicode, o autor desta biblioteca mapeou todos os tipos de conjuntos regionais de caracteres, facilitando o trabalho com diferentes idiomas.

Eu notei algo muito estranho com o \b ao usar o Unicode:

 /\bo/.test("pop"); // false (obviously) /\bä/.test("päp"); // true (what..?) /\Bo/.test("pop"); // true /\Bä/.test("päp"); // false (what..?) 

Parece que o significado de \b e \B está invertido, mas apenas quando usado com Unicode não-ASCII? Pode haver algo mais profundo acontecendo aqui, mas não tenho certeza do que é.

Em qualquer caso, parece que o limite da palavra é o problema, não os caracteres Unicode em si. Talvez você deva apenas replace \b por (^|[\s\\/-_&]) , pois isso parece funcionar corretamente. (Torne sua lista de símbolos mais abrangente que a minha, no entanto.)

Minha ideia é pesquisar com códigos representando as letras finlandesas

new RegExp("\\b"+asciiOnly(searchterm), "gi").test(asciiOnly(title))

Minha ideia original era usar o encodeURI simples, mas o sinal% parecia interferir no regexp.

http://jsfiddle.net/7TsxB/5/

Eu escrevi uma function crua usando encodeURI para codificar cada caractere com código acima de 128, mas removendo seu% e adicionando ‘QQ’ no começo. Não é o melhor marcador, mas não consegui trabalhar com nenhum alfanumérico.

Eu tive um problema semelhante, mas tive que replace uma matriz de termos. Todas as soluções, que eu encontrei, não funcionaram, se dois termos estivessem no texto ao lado um do outro (porque seus limites se sobrepunham). Então eu tive que usar uma pequena abordagem modificada:

 var text = "Ještě. že; \"už\" à. Fürs, 'anlässlich' že že že."; var terms = ["à","anlässlich","Fürs","už","Ještě", "že"]; var replaced = []; var order = 0; for (i = 0; i < terms.length; i++) { terms[i] = "(^\|[ \n\r\t.,;'\"\+!?-])(" + terms[i] + ")([ \n\r\t.,;'\"\+!?-]+\|$)"; } var re = new RegExp(terms.join("|"), ""); while (true) { var replacedString = ""; text = text.replace(re, function replacer(match){ var beginning = match.match("^[ \n\r\t.,;'\"\+!?-]+"); if (beginning == null) beginning = ""; var ending = match.match("[ \n\r\t.,;'\"\+!?-]+$"); if (ending == null) ending = ""; replacedString = match.replace(beginning,""); replacedString = replacedString.replace(ending,""); replaced.push(replacedString); return beginning+"{{"+order+"}}"+ending; }); if (replacedString == "") break; order += 1; } 

Veja o código em um violino: http://jsfiddle.net/antoninslejska/bvbLpdos/1/

A expressão regular é inspirada em: http://breakthebit.org/post/3446894238/word-boundaries-in-javascripts-regular

Eu não posso dizer que acho a solução elegante ...

O que você está procurando é o padrão de limites de palavras Unicode:

http://unicode.org/reports/tr29/tr29-9.html#Word_Boundaries

Existe uma implementação JavaScript aqui (unciodejs.wordbreak.js)

https://github.com/wikimedia/unicodejs