Использование JavaScript для сопоставления текста с / без ударных символов - PullRequest
17 голосов
/ 18 апреля 2011

Я использую поиск на основе 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;
}

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

Ответы [ 9 ]

18 голосов
/ 18 апреля 2011

это должно помочь: это называется складной акцент:

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

15 голосов
/ 16 августа 2018

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

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

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

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

var string_norm = string.normalize('NFD').replace(/[\u0300-\u036f]/g, "");
console.log(string_norm);
12 голосов
/ 08 апреля 2013

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

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

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;
};
7 голосов
/ 18 апреля 2011

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

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

}());
3 голосов
/ 25 сентября 2018

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

Спасибо!

0 голосов
/ 16 октября 2018

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

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

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

В качестве альтернативы вы пытаетесь localecompare

'être'.localeCompare('etre',undefined,{sensitivity: 'base'})
0 голосов
/ 24 февраля 2018

Вы также можете использовать http://fusejs.io для нечеткого поиска.

0 голосов
/ 25 мая 2011

Я сделал прототип этой версии:

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 голосов
/ 18 апреля 2011

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

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

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

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

...