Использование JavaScript для выполнения текстовых совпадений с/без акцентированных символов

Я использую поиск на основе AJAX для имен, которые пользователь ищет в текстовом поле.

Я делаю предположение, что все имена в базе данных будут транслитерированы в европейские алфавиты (т.е. ни кириллицы, ни японцы, ни китайцы). Однако имена будут по-прежнему содержать символы с акцентом, такие как ç, ê и даже č и ć.

Простой поиск, такой как "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;
}

Помимо функции подстановки, подобной этой, есть ли лучший способ? Возможно, чтобы "деактивировать" сравниваемую строку?

Ответы

Ответ 2

Есть способ "деактивировать" сравниваемую строку без использования функции подстановки, которая перечисляет все акценты, которые вы хотите удалить…

Вот самое простое решение, которое я могу придумать, чтобы удалить акценты (и другие диакритические знаки) из строки.

Посмотрите это в действии:

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

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

Ответ 3

Наткнулся на эту старую ветку и подумал, что я попробую свои силы в выполнении быстрой функции. Я полагаюсь на упорядочивание переменных-разделителей, устанавливающих переменные OR, когда они совпадают в вызываемой функции replace(). Моя цель состояла в том, чтобы использовать как можно больше стандартную функцию javascript replace() для реализации regex, чтобы тяжелая обработка могла выполняться в низкоуровневом пространстве, оптимизированном для браузера, вместо дорогих сравнений javascript по типу char,

Это совсем не научно, но мой старый телефон Android IDEOS Huawei работает медленно, когда я подключаю другие функции в этой теме к своему автозаполнению, в то время как эта функция движется вперед:

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 так же, как вы используете: содержит в селекторе:

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

Ответ 4

Нет более простого способа "деактивировать", о котором я могу думать, но ваша замена может быть упрощена:

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] + ']';
        });
    };

}());

Ответ 5

Я искал и проголосовал за ответ 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

Обратите внимание, однако, что полная поддержка по-прежнему отсутствует для некоторых мобильных браузеров !!!

До тех пор продолжайте следить за полной поддержкой на ВСЕХ платформах и env.

Это все?

Нет, мы можем пойти дальше и использовать функцию 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"

Благодарю вас !

Ответ 6

Я искал что-то подобное, но вместо создания регулярного выражения я просто хотел заменить акцентированные символы на их эквиваленты ASCII. Вдохновленный ответом 999 и статьей в 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!"

Ответ 7

Я сделал версию Prototype этого:

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

Ответ 8

Я думаю, что это самое лучшее решение

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

Он вернет 0, если две строки одинаковы, игнорируя акценты.

Или вы попробуйте localecompare

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

Ответ 9

Во-первых, я бы рекомендовал оператор switch вместо длинной строки if-else, если...

Тогда я не уверен, почему вам не нравится ваше текущее решение. Это, безусловно, самый чистый. Что вы подразумеваете, не принимая во внимание "всех персонажей"?

В JavaScript нет стандартного метода для сопоставления акцентированных букв с буквами ASCII за пределами использования сторонней библиотеки, поэтому тот, который вы написали, не хуже любого.

Кроме того, "ß" я считаю, что карты относятся к "ss", а не к одному "s". И остерегайтесь "i" с и без точек на турецком языке - я считаю, что они относятся к разным буквам.

Ответ 10

Вы также можете использовать http://fusejs.io, который описывает себя как "Легкая библиотека нечеткого поиска. Нулевые зависимости", для нечеткого поиска.