web-dev-qa-db-ja.com

JavaScriptを使用して、アクセント付き文字を含む/含まないテキスト一致を実行する

ユーザーがテキストボックスで検索する名前にAJAXベースのルックアップを使用しています。

私は、データベース内のすべての名前がヨーロッパのアルファベットに文字変換される(つまり、キリル文字、日本語、中国語ではない)と仮定しています。ただし、名前にはç、ê、さらにはčやevenなどのアクセント付き文字が含まれます。

「Micic」のような単純な検索は「Mičić」とは一致しませんが、ユーザーの期待は一致します。

AJAXルックアップは正規表現を使用して一致を判断します。この関数を使用して正規表現の比較を変更し、よりアクセントのある文字を一致させようとしました。ただし、これは少し扱いに​​くいです。すべてのキャラクターを考慮に入れてください。

function makeComp (input)
{
    input = input.toLowerCase ();
    var output = '';
    for (var i = 0; i < input.length; i ++)
    {
        if (input.charAt (i) == 'a')
            output = output + '[aàáâãäåæ]'
        else if (input.charAt (i) == 'c')
            output = output + '[cç]';
        else if (input.charAt (i) == 'e')
            output = output + '[eèéêëæ]';
        else if (input.charAt (i) == 'i')
            output = output + '[iìíîï]';
        else if (input.charAt (i) == 'n')
            output = output + '[nñ]';
        else if (input.charAt (i) == 'o')
            output = output + '[oòóôõöø]';
        else if (input.charAt (i) == 's')
            output = output + '[sß]';
        else if (input.charAt (i) == 'u')
            output = output + '[uùúûü]';
        else if (input.charAt (i) == 'y')
            output = output + '[yÿ]'
        else
            output = output + input.charAt (i);
    }
    return output;
}

このような置換関数は別として、もっと良い方法はありますか?たぶん、比較されている文字列を「まとも」にするには?

26
Philip

削除するすべてのアクセントをリストする置換関数を使用せずに「比較される文字列を「deaccent」」する方法があります…

これが 最も簡単な解決策です 私は文字列からアクセント(および他の発音区別符号)を削除することを考えることができます。

実際に見てください:

var string = "Ça été Mičić. ÀÉÏÓÛ";
console.log(string);

var string_norm = string.normalize('NFD').replace(/[\u0300-\u036f]/g, "");
console.log(string_norm);
20
Takit Isy

これは役立つはずです:その呼び出されたアクセント折りたたみ:

http://alistapart.com/article/accent-folding-for-auto-complete

16
herostwist

この古いスレッドに出くわし、私は高速な機能を実行するために自分の手を試してみようと思いました。 replace()が呼び出している関数で一致する場合、パイプで区切られたOR設定変数の順序に依存しています。私の目標は、標準のregex実装javascriptのreplace()関数を可能な限り使用して、負荷の高いjavascriptの文字単位の比較ではなく、低レベルのブラウザー最適化スペースで重い処理を実行できるようにすることでした。

それはまったく科学的ではありませんが、私の古いHuawei IDEOS Androidこのスレッドの他の関数をオートコンプリートにプラグインすると、電話が遅くなりますが、この関数は圧縮されます:

function accentFold(inStr) {
  return inStr.replace(
    /([àáâãäå])|([ç])|([èéêë])|([ìíîï])|([ñ])|([òóôõöø])|([ß])|([ùúûü])|([ÿ])|([æ])/g, 
    function (str, a, c, e, i, n, o, s, u, y, ae) {
      if (a) return 'a';
      if (c) return 'c';
      if (e) return 'e';
      if (i) return 'i';
      if (n) return 'n';
      if (o) return 'o';
      if (s) return 's';
      if (u) return 'u';
      if (y) return 'y';
      if (ae) return 'ae';
    }
  );
}

JQuery開発者の場合、この関数を使用する便利な例を以下に示します。 :icontainsは、セレクターで:containsを使用するのと同じ方法で使用できます。

jQuery.expr[':'].icontains = function (obj, index, meta, stack) {
  return accentFold(
    (obj.textContent || obj.innerText || jQuery(obj).text() || '').toLowerCase()
  )
    .indexOf(accentFold(meta[3].toLowerCase())
  ) >= 0;
};
12

私が考えることができる「まともな」へのより簡単な方法はありませんが、あなたの置換はもう少し合理化されるかもしれません:

var makeComp = (function(){

    var accents = {
            a: 'àáâãäåæ',
            c: 'ç',
            e: 'èéêëæ',
            i: 'ìíîï',
            n: 'ñ',
            o: 'òóôõöø',
            s: 'ß',
            u: 'ùúûü',
            y: 'ÿ'
        },
        chars = /[aceinosuy]/g;

    return function makeComp(input) {
        return input.replace(chars, function(c){
            return '[' + c + accents[c] + ']';
        });
    };

}());
7
James

私は検索して賛成しました herostwist 回答ですが、検索を続けましたが、実際には、JavaScriptの中核となる最新のソリューションがあります( string.localeCompare 関数)

var a = 'réservé'; // with accents, lowercase
var b = 'RESERVE'; // no accents, uppercase

console.log(a.localeCompare(b));
// expected output: 1
console.log(a.localeCompare(b, 'en', {sensitivity: 'base'}));
// expected output: 0

注、ただし、一部のモバイルブラウザでは完全なサポートがまだありません!!!

それまでは、すべてのプラットフォームと環境での完全なサポートに注意してください。

それだけですか?

いいえ、さらに先に進んで string.toLocaleLowerCase 関数を使用できます。

var dotted = 'İstanbul';

console.log('EN-US: ' + dotted.toLocaleLowerCase('en-US'));
// expected output: "istanbul"

console.log('TR: ' + dotted.toLocaleLowerCase('tr'));
// expected output: "istanbul"

ありがとうございました !

3

私はこれのプロトタイプバージョンを作りました:

String.prototype.strip = function() {
  var translate_re = /[öäüÖÄÜß ]/g;
  var translate = {
    "ä":"a", "ö":"o", "ü":"u",
    "Ä":"A", "Ö":"O", "Ü":"U",
    " ":"_", "ß":"ss"   // probably more to come
  };
    return (this.replace(translate_re, function(match){
        return translate[match];})
    );
};

次のように使用:

var teststring = 'ä ö ü Ä Ö Ü ß';
teststring.strip();

これは文字列をa_o_u_A_O_U_ssに変更します

0
Jan Hagge

これが最も近いソリューションだと思います

var nIC = new Intl.Collator(undefined , {sensitivity: 'base'})
var cmp = nIC.compare.bind(nIC)

2つの文字列が同じ場合、アクセントを無視して0を返します。

または、localecompareを試してください

'être'.localeCompare('etre',undefined,{sensitivity: 'base'})
0
user1221780

私は似たようなものを探していましたが、正規表現を作成する代わりに、アクセント付き文字をASCII同等のものに置き換えたいと思っていました。999の返信とA List Apart( http://www.alistapart.com/articles/accent-folding-for-auto-complete/ )私は次の関数をopに追加しました。もちろん、特定の実装に合わせて変更できます。

var accent_fold = (function () {
    var accent_map = {
        'à': 'a', 'á': 'a', 'â': 'a', 'ã': 'a', 'ä': 'a', 'å': 'a', // a
        'ç': 'c',                                                   // c
        'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e',                     // e
        'ì': 'i', 'í': 'i', 'î': 'i', 'ï': 'i',                     // i
        'ñ': 'n',                                                   // n
        'ò': 'o', 'ó': 'o', 'ô': 'o', 'õ': 'o', 'ö': 'o', 'ø': 'o', // o
        'ß': 's',                                                   // s
        'ù': 'u', 'ú': 'u', 'û': 'u', 'ü': 'u',                     // u
        'ÿ': 'y'                                                    // y
    };

    return function accent_fold(s) {
        if (!s) { return ''; }
        var ret = '';
        for (var i = 0; i < s.length; i++) {
            ret += accent_map[s.charAt(i)] || s.charAt(i);
        }
        return ret;
    };
} ());

使用法:

var someText = "lôõk mä, nø hånds!";
someText = accent_fold(someText);
// someText now contains: "look ma, no hands!"
0
Mark van Dijk