web-dev-qa-db-fra.com

Javascript RegExp + limites du mot + caractères unicode

Je construis la recherche et je vais utiliser javascript autocomplete avec elle. Je viens de Finlande (langue finlandaise), je dois donc composer avec des caractères spéciaux comme ä, ö et å

Lorsque l'utilisateur tape du texte dans le champ de saisie de la recherche, je tente de faire correspondre le texte aux données.

Voici un exemple simple qui ne fonctionne pas correctement si l'utilisateur tape par exemple "ää". Même chose avec "ä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/

Alors, comment puis-je faire en sorte que ces caractères ä, ö et å fonctionnent avec javascript regex? 

Je pense que je devrais utiliser des codes unicode, mais comment dois-je faire cela? Les codes pour ces caractères sont: [\ U00C4,\u00E4,\u00C5,\u00E5,\u00D6,\u00F6]

=> äÄåÅöÖ

36
user1394520

Il semble y avoir un problème avec Regex et la limite de mot \b faisant correspondre le début d'une chaîne avec un caractère de départ hors de la plage normale de 256 octets.

Au lieu d'utiliser \b, essayez d'utiliser (?:^|\\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);   
}

Panne:

(?: parenthesis () forme un groupe de capture dans Regex. Les parenthèses ont commencé par un point d’interrogation et les deux points ?: forment un groupe non capturant. Ils ne font que regrouper les termes ensemble

^ le symbole caret correspond au début d'une chaîne

| la barre est l'opérateur "ou". 

\s correspond à un espace (apparaît sous la forme \\s dans la chaîne car nous devons échapper à la barre oblique inversée)

) ferme le groupe

Ainsi, au lieu d'utiliser \b, qui correspond aux limites de Word et ne fonctionne pas pour les caractères unicode, nous utilisons un groupe de non-capture qui correspond au début d'une chaîne OR d'espaces.

38
mowwwalker

La classe de caractères \b dans JavaScript RegEx n'est vraiment utile qu'avec le codage simple ASCII. \b est un code de raccourci pour la limite entre les ensembles \w et \W ou \w et le début ou la fin de la chaîne. Ces jeux de caractères ne prennent en compte que les caractères ASCII "Word", où \w est égal à [a-zA-Z0-9_] et \W est la négation de cette classe.

Cela rend les classes de caractères RegEx largement inutiles pour traiter avec un langage réel.

\s devrait fonctionner pour ce que vous voulez faire, à condition que les termes de recherche ne soient délimités que par des espaces.

17
Noah Freitas

cette question est ancienne, mais je pense avoir trouvé une meilleure solution pour les limites dans les expressions rationnelles avec des lettres unicode. En utilisant XRegExp, vous pouvez implémenter une limite\b valide développant cette 

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

le résultat est un long caractère 4000+, mais il semble fonctionner assez performant.

Quelques explications: (? =) Est un préfixe de longueur nulle qui recherche une limite de début ou de fin ou un caractère Unicode non alphabétique. La pensée la plus importante est la prévision, car le\b ne capture rien: il est simplement vrai ou faux.

9
max masetti

Je vous recommanderais d'utiliser XRegExp lorsque vous devez travailler avec un jeu de caractères spécifique à partir d'Unicode, l'auteur de cette bibliothèque a mis en correspondance toutes sortes de jeux de caractères régionaux facilitant le travail dans différentes langues.

6
micnic

J'ai remarqué quelque chose de vraiment bizarre avec \b sous Unicode:

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

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

Il semble que les significations de \b et \B soient inversées, mais uniquement lorsqu'elles sont utilisées avec Unicode non-ASCII? Il se peut que quelque chose de plus profond se passe ici, mais je ne suis pas sûr de ce que c'est.

Dans tous les cas, il semble que le problème soit la limite de Word, et non les caractères Unicode eux-mêmes. Peut-être devriez-vous simplement remplacer \b par (^|[\s\\/-_&]), car cela semble fonctionner correctement. (Faites cependant votre liste de symboles plus complète que la mienne.)

2
apsillers

Ce que vous recherchez, c'est la norme de limites de mots Unicode:

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

Il y a une implémentation JavaScript ici (unciodejs.wordbreak.js)

https://github.com/wikimedia/unicodejs

0
Ed.

Mon idée est de rechercher avec des codes représentant les lettres finlandaises

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

Mon idée de départ était d’utiliser plain encodeURI, mais le signe% semblait interférer avec l’expression rationnelle. 

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

J'ai écrit une fonction brute utilisant encodeURI pour encoder tous les caractères dont le code est supérieur à 128, mais en supprimant son% et en ajoutant 'QQ' au début. Ce n'est pas le meilleur marqueur, mais je ne pouvais pas utiliser du matériel non alphanumérique.

0
Heitor Chang

J'ai eu un problème similaire, mais j'ai dû remplacer un tableau de termes. Toutes les solutions, que j'ai trouvées, ne fonctionnaient pas si deux termes étaient dans le texte l'un à côté de l'autre (car leurs limites se chevauchaient). J'ai donc dû utiliser une approche légèrement modifiée:

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

Voir le code dans un violon: http://jsfiddle.net/antoninslejska/bvbLpdos/1/

L'expression régulière est inspirée par: http://breakthebit.org/post/3446894238/Word-boundaries-in-javascripts-regular

Je ne peux pas dire que je trouve la solution élégante ...

0
Antonín Slejška