Эффективно заменить все символы с диакритическими знаками в строке?

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

Вот что я имею в виду (обратите внимание, что это относится к немецкому тексту, другие языки сортируются по-другому):

native sorting gets it wrong: a b c o u z ä ö ü
collation-correct would be:   a ä b c o ö u ü z

По сути, мне нужно, чтобы все вхождения «ä» в данной строке заменялись на «а» (и так далее). Таким образом, результат собственной сортировки будет очень близок к тому, что ожидает пользователь (или к тому, что вернет база данных).

В других языках есть средства для этого: Python поставляет str.translate(), в Perl есть tr/…/…/, XPath имеет функцию translate(), ColdFusion имеет ReplaceList(). Но как насчет JavaScript?

Вот что у меня есть прямо сейчас.

// s would be a rather short string (something like 
// 200 characters at max, most of the time much less)
function makeSortString(s) {
  var translate = {
    "ä": "a", "ö": "o", "ü": "u",
    "Ä": "A", "Ö": "O", "Ü": "U"   // probably more to come
  };
  var translate_re = /[öäüÖÄÜ]/g;
  return ( s.replace(translate_re, function(match) { 
    return translate[match]; 
  }) );
}

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

Кто-нибудь может придумать что-нибудь более эффективное?


Ответы ниже делятся на две категории:

  1. Функции замены строк разной степени полноты и эффективности (о чем я изначально спрашивал)
  2. позднее упоминание из String#localeCompare, который теперь является широко поддерживаемый среди JS-движков (не так много во время вопроса) и мог бы решить эту категорию проблем гораздо более элегантно.

Вы ошибаетесь в своем предположении, что пользователь ожидает, что "ä" будет отсортировано с "a". В шведском алфавите 29 букв: abcdefghijklmnopqrstuvwxyzåäö, а также в датском / норвежском: abcdefghijklmnopqrstuvwxyzæøå. Ожидаемый порядок: «Апельсин», «Банан», «Аппле».

some 09.03.2009 22:14

Я знаю. Решение предназначалось для сортировки немецкого текста. Даже там это не правильный, но достаточно хорошее для варианта использования. Этот вопрос никогда не задумывался как поиск алгоритма «решает все проблемы».

Tomalak 09.03.2009 22:24

Я немного перефразировал вопрос, чтобы прояснить это с самого начала.

Tomalak 09.03.2009 22:34

@Tomalak: Я нашел ваш вопрос, когда переходил по ссылке из другого вопроса о «u» и «ü», и мне пришлось возразить. Но поскольку вы сейчас пояснили, что это было для немецкого языка, мне больше нечего возражать.

some 09.03.2009 23:48

@some: Я предпочитаю короткое обсуждение в комментариях, а не голосование "против" в любое время. К сожалению, здесь есть люди, которые сначала голосуют против, а потом задают вопросы (если вообще). Следствие: ваш комментарий был оценен по достоинству. :)

Tomalak 10.03.2009 00:24

@Tomalak: К сожалению, есть люди, которые голосуют против без всякой видимой причины, даже правильные ответы и кристально ясные вопросы ... Интересно, заметили ли они, что сами теряют 1 балл? Я предпочитаю оставить комментарий, чтобы автор мог внести пояснения / исправления. ИМХО, что лучше.

some 10.03.2009 00:53

Просто чтобы вы знали, у меня есть вилка tableorter, в которой я модифицировал оригиналsortLocaleCompare вариант, чтобы автоматически заменять эти строки с диакритическими знаками; пожалуйста, смотрите эта демонстрация для более подробной информации. Если это все еще не работает для вас, попробуйте эта демонстрация, который заменяет сортировщик текста по умолчанию на sugar.js.

Mottie 19.12.2013 00:47

Спасибо @Mottie. (Я считаю, что sortLocaleCompare даже не существовало, когда я впервые написал этот вопрос.)

Tomalak 19.12.2013 10:19

На самом деле он существовал в v2.0.5 (недокументированный), и все, что он делал, это return a.localeCompare(b); внутри сортировки.

Mottie 20.12.2013 11:31

см. более свежее решение stackoverflow.com/a/18391901/759452

Adrien Be 16.09.2014 18:52

Есть пакет NPM, который делает именно это, github.com/andrewrk/node-diacritics.

Gajus 03.04.2016 22:11

Отвечает ли это на ваш вопрос? Удаление диакритических знаков и диакритических знаков в строке в JavaScript

Jeffrey Yasskin 06.08.2020 06:53
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
120
12
130 811
21
Перейти к ответу Данный вопрос помечен как решенный

Ответы 21

Ответ принят как подходящий

Я не могу говорить о том, что вы пытаетесь сделать конкретно с самой функцией, но если вам не нравится, что регулярное выражение создается каждый раз, вот два решения и некоторые предостережения по каждому из них.

Вот один из способов сделать это:

function makeSortString(s) {
  if (!makeSortString.translate_re) makeSortString.translate_re = /[öäüÖÄÜ]/g;
  var translate = {
    "ä": "a", "ö": "o", "ü": "u",
    "Ä": "A", "Ö": "O", "Ü": "U"   // probably more to come
  };
  return ( s.replace(makeSortString.translate_re, function(match) { 
    return translate[match]; 
  }) );
}

Это, очевидно, сделает регулярное выражение свойством самой функции. Единственное, что вам может не понравиться в этом (или вы можете, я думаю, это зависит), это то, что регулярное выражение теперь может быть изменено за пределами тела функции. Итак, кто-то может сделать это, чтобы изменить внутреннее используемое регулярное выражение:

makeSortString.translate_re = /[a-z]/g;

Так что вариант есть.

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

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

Надеюсь, это будет вам полезно.


ОБНОВЛЕНИЕ: это рано, и я не знаю, почему я не видел очевидного раньше, но также может быть полезно поместить объект translate в закрытие:

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

Я пытаюсь сделать так, чтобы сортировка плагина jQuery tablesorter работала правильно для табличных данных на немецком языке. Плагин может использовать определяемую пользователем функцию для извлечения строки для сортировки, что мне и нужно сделать, иначе полученный порядок сортировки будет неправильным.

Tomalak 13.11.2008 18:18

Неужели эта функция настолько неэффективна? Что вы сделали с тестированием?

Jason Bunting 13.11.2008 18:30

Я не хотел сказать, что моя реализация была неэффективной. Это почти самый эффективный способ сделать это, о чем я могу думать. Но я не могу придумать все, поэтому я надеялся, что существует какой-то действительно умный способ манипулирования строками, о котором я не подозревал.

Tomalak 13.11.2008 18:37

Понятно - думаю, вашего решения достаточно; поскольку я мог увидеть применение этой функции в долгосрочной перспективе, я провел базовое тестирование. Я сделал 5000 итераций для строки из 200 символов, содержащей хотя бы один из этих символов, каждые 8 ​​символов, и это заняло около 500 мс.

Jason Bunting 13.11.2008 19:20

Кстати, это тестирование проводилось в FF. В Chrome это работало примерно так же; поскольку JS-движок Chrome (V8) быстрее, в общем, стоит отметить этот факт, FWIW.

Jason Bunting 13.11.2008 19:36

Спасибо за ваше время, очень признателен. Я проведу собственное тестирование (но не сегодня, здесь 18:00) и опубликую здесь свои выводы.

Tomalak 13.11.2008 19:55

На самом деле мне никогда не приходилось писать тестовый пример для сравнения результатов. Я оставил это открытым как напоминание, что когда-нибудь это сделаю, но было бы несправедливо не принять ответ, который я использовал, поэтому я делаю это сейчас. Извините за столь долгую задержку.

Tomalak 04.03.2009 21:12

Не беспокойтесь - надеюсь, я был вам полезен!

Jason Bunting 04.03.2009 21:33

Ты был. ;-) Я выложил то, что у меня сейчас работает, может кому-то это пригодится.

Tomalak 05.03.2009 14:29

Я воспользовался ответом этого человека на аналогичную проблему: stackoverflow.com/a/5912746/81633

stephen 07.03.2013 01:05

Кодировка для венгерского регулярного выражения: var translate_re = /[éáűőúöüóíÉÁŰPŐÚÖÜÓÍ]/g; var translate = { "é": "e", "á": "a", "ű": "u", "ő": "o", "ú": "u", "ö": "o", "ü": "u", "ó": "o", "í": "i", "É": "E", "Á": "A", "Ű": "U", "Ő": "O", "Ú": "U", "Ö": "O", "Ü": "U", "Ó": "O", "Í": "I" };

zsitro 10.04.2013 12:55

Кодировка для регулярного выражения румынского языка: var translate_re = /[șțăîâȘȚĂÎÂ]/g; var translate = { "ș": "s", "ț": "t", "ă": "a", "î": "i", "â": "a", "Ș": "S", "Ț": "T", "Ă": "A", "Î": "I", "Â": "A" };

Attila Fulop 01.06.2015 12:48

Вот что я использую на основе решения Джейсона Бантинга.

Все это для подключаемый модуль jQuery tablesorter: для (почти правильной) сортировки неанглийских таблиц с помощью плагина tableorter необходимо использовать настраиваемый textExtraction функция.

Этот:

  • переводит самые распространенные буквы с ударением в буквы без ударения (список поддерживаемых букв легко расширяется)
  • изменяет даты в немецком формате ('dd.mm.yyyy') на распознанный формат ('yyyy-mm-dd')

Будьте осторожны, сохраняя файл JavaScript в кодировке UTF-8, иначе он не сработает.

// file encoding must be UTF-8!
function getTextExtractor()
{
  return (function() {
    var patternLetters = /[öäüÖÄÜáàâéèêúùûóòôÁÀÂÉÈÊÚÙÛÓÒÔß]/g;
    var patternDateDmy = /^(?:\D+)?(\d{1,2})\.(\d{1,2})\.(\d{2,4})$/;
    var lookupLetters = {
      "ä": "a", "ö": "o", "ü": "u",
      "Ä": "A", "Ö": "O", "Ü": "U",
      "á": "a", "à": "a", "â": "a",
      "é": "e", "è": "e", "ê": "e",
      "ú": "u", "ù": "u", "û": "u",
      "ó": "o", "ò": "o", "ô": "o",
      "Á": "A", "À": "A", "Â": "A",
      "É": "E", "È": "E", "Ê": "E",
      "Ú": "U", "Ù": "U", "Û": "U",
      "Ó": "O", "Ò": "O", "Ô": "O",
      "ß": "s"
    };
    var letterTranslator = function(match) { 
      return lookupLetters[match] || match;
    }

    return function(node) {
      var text = $.trim($(node).text());
      var date = text.match(patternDateDmy);
      if (date)
        return [date[3], date[2], date[1]].join("-");
      else
        return text.replace(patternLetters, letterTranslator);
    }
  })();
}

Вы можете использовать это так:

$("table.sortable").tablesorter({ 
  textExtraction: getTextExtractor()
}); 

Не знаю, увидит ли кто-нибудь мой комментарий, но мне нужна та же функция для некоторых акцентированных букв на португальском языке, и мне не удается заставить ее работать. Должны ли соответствующие буквы в моем php-файле вызываться «html-кодом»: & Iacute; или просто набрав букву «Í»? Пробовал оба, ничего не работает. И да, я изменил функцию js в соответствии со своими потребностями с помощью букв Í и í, а мой js закодирован в utf-8.

kevin 17.03.2010 00:28

@kevin: Конечно, кто-то заметил комментарий. ;-) Символ в вашем HTML (который, как я полагаю, создается этим файлом PHP) может быть Í или фактическим Í. Это не имеет значения, если настройки кодировки верны (фактическая кодировка файла PHP, кодировка файла, воспринимаемая сервером PHP, заголовок HTTP Content-Type, метатеги HTML). Использование объекта HTML может быть самым безопасным. Если файл .js имеет кодировку UTF-8, он должен обслуживаться как таковой (text/javascript; Charset=UTF-8), тогда все должно быть в порядке.

Tomalak 17.03.2010 01:32

Спасибо, что заметили ;-), я проверял и пробовал разными способами то, что вы сказали, просто не получается. Может ли это быть из-за того, что другие файлы js вызываются на той же странице php? Если вы хотите взглянуть, это здесь: schulz-al.tempsite.ws/br/?page_id=51. Спасибо за помощь, оценил.

kevin 18.03.2010 18:08

@kevin: Кстати, проверьте свои ссылки на sitemap-up.gif и sitemap-down.gif, я получаю для них 401 доступ запрещен.

Tomalak 18.03.2010 19:48

@kevin: Следующее: ваши скрипты обслуживаются как Content-Type: text/html без параметра Charset. Они должны быть как минимум Content-Type: text/javascript;. Кроме того, ваш метод GetTextExtractor() (тот, что есть в jquery.tablesorter.min.js) довольно сильно отличается от моей функции, и вы не знаете, почему вы думаете, что ваш метод может работать. ;-) Совет: поместите средство извлечения текста в scripts.js, а не в код плагина tableorter. Не трогайте код плагина, чтобы избежать головной боли в будущем.

Tomalak 18.03.2010 19:57

Да уж видел изображения п.б., решил. Что касается <code> Content-Type: text / javascript </code>, все мои скрипты вызываются таким образом <code> <script type = "text / javascript" src = "<? Php bloginfo ('template_url'); ?> / js / jquery.tablesorter.min.js "charset = " utf-8 "> </script> </code>, поэтому я не понимаю, что вы имеете в виду. Я просто сделал то, что вы предлагали, скопировал обратно ваш js-код в новый файл scripts.js и добавил мои буквы «Í» и «í», по-прежнему ничего, схожу с ума и чувствую себя тупым. В любом случае большое спасибо за помощь.

kevin 18.03.2010 22:09

@kevin: Мне жаль говорить, что есть причина чувствовать себя глупо. ;-) Вы скопировали мой код $("table.sortable").tablesorter(…);, но на самом деле ваш стол - это $("table.tablesorter"). Также нет необходимости повторно звонить в tablesorter(). Как только вы внесете это изменение, оно будет работать - я только что протестировал с помощью FireBug.

Tomalak 18.03.2010 22:52

Омг, это действительно было довольно глупо ... Большое спасибо за помощь, Томалак, очень признателен, теперь он отлично работает. Мне также пришлось вызвать извлечение символов <code> {textExtraction: GetTextExtractor ()} </code> после вызова виджета зебры <code> $ .tablesorter.defaults.widgets = ['zebra']; </code>, чтобы получить все это вместе. Еще раз спасибо!

kevin 18.03.2010 23:34

@kevin: Рад слышать, что это все-таки сработало. :) P.S .: Я был бы признателен за ответное голосование. ;)

Tomalak 19.03.2010 00:07

Конечно, как я могу это сделать? (это щелчок по значку флажка "это отличный комментарий"?)

kevin 19.03.2010 00:21

@kevin: Нет, нажимая кнопки голосования в верхнем левом углу ответа. ;) За комментарии тоже можно проголосовать, но только голоса за вопросы или ответы создают репутацию, которая является основной валютой этого сайта. ;)

Tomalak 19.03.2010 00:29

Отличный код! Может быть, вы могли бы сделать из этого GitHub Gist?

Alex D 06.07.2012 20:06

У меня все еще была проблема с сортировкой, например: Šalat, Sup. Это неправильный порядок, поэтому я сделал что-то вроде этого - «Š»: «Szz», «š»: «szz», это должно быть почти на 100% эффективным.

mesnicka 26.04.2013 11:26

Я сделал прототипную версию этого:

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

это не работает. Однако, если я использую var newstr = teststring.strip(); и console.info(), тогда он работает - jsfiddle. Спасибо, мужик, это самый лаконичный и читаемый метод.

Andrejs 15.06.2015 18:09

Я думаю, что это могло бы работать немного чище / лучше (хотя я не тестировал его производительность):

String.prototype.stripAccents = function() {
    var translate_re = /[àáâãäçèéêëìíîïñòóôõöùúûüýÿÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ]/g;
    var translate = 'aaaaaceeeeiiiinooooouuuuyyAAAAACEEEEIIIINOOOOOUUUUY';
    return (this.replace(translate_re, function(match){
        return translate.substr(translate_re.source.indexOf(match)-1, 1); })
    );
};

Или, если вы все еще слишком беспокоитесь о производительности, давайте возьмем лучшее из обоих миров:

String.prototype.stripAccents = function() {
    var in_chrs =  'àáâãäçèéêëìíîïñòóôõöùúûüýÿÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ',
        out_chrs = 'aaaaaceeeeiiiinooooouuuuyyAAAAACEEEEIIIINOOOOOUUUUY', 
        transl = {};
    eval('var chars_rgx = /['+in_chrs+']/g');
    for(var i = 0; i < in_chrs.length; i++){ transl[in_chrs.charAt(i)] = out_chrs.charAt(i); }
    return this.replace(chars_rgx, function(match){
        return transl[match]; });
};

РЕДАКТИРОВАТЬ (автор @Tomalak)

Я ценю идею. Однако есть несколько ошибок в реализации, как указано в комментарии ниже.

Вот как я бы это реализовал.

var stripAccents = (function () {
  var in_chrs   = 'àáâãäçèéêëìíîïñòóôõöùúûüýÿÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ',
      out_chrs  = 'aaaaaceeeeiiiinooooouuuuyyAAAAACEEEEIIIINOOOOOUUUUY', 
      chars_rgx = new RegExp('[' + in_chrs + ']', 'g'),
      transl    = {}, i,
      lookup    = function (m) { return transl[m] || m; };

  for (i=0; i<in_chrs.length; i++) {
    transl[ in_chrs[i] ] = out_chrs[i];
  }

  return function (s) { return s.replace(chars_rgx, lookup); }
})();

Почему вы думаете, что это работает лучше? Я предполагаю, что поиск объекта на много быстрее, чем String.indexOf().

Tomalak 13.12.2011 18:23

Tomalak, я добавил еще один способ сделать это, который объединяет лучшее из обоих миров (читаемость и производительность), я мог бы в конечном итоге сделать еще один шаг и кэшировать объект char_rgx, но я не думаю, что это имеет большой смысл, если только при работе с точность в реальном времени ...

Martin_Lakes 13.12.2011 22:03

Извините, но в этом коде есть несколько ошибок. Во-первых, ненадлежащее использование eval(). Для этого есть new RegExp(). Во-вторых, он изменяет прототип String. Модификация встроенных типов данных очень не одобряется. В-третьих, функция запускает цикл для каждого символа при каждом вызове. Это то, чего я пытался избежать в первую очередь. Это означает, что он исправляет удобочитаемость за счет производительности, что я считаю плохим компромиссом. Я ценю идею, но исполнение не оптимально. :)

Tomalak 13.12.2011 23:38

@Tomalak, это отличный способ сделать это! Мне просто интересно, почему вы возвращаете функцию вместо того, чтобы передавать "s" в первую очередь var stripAccents = function(s){ var in_chrs = ... }? jsfiddle

pmrotule 21.05.2015 22:35

Поскольку возвращение функции закрывает переменные и функцию во внешней области видимости, поэтому их не нужно переопределять каждый раз при вызове stripAccents(). Смотрите закрытия.

Tomalak 21.05.2015 22:43

Вот более полная версия, основанная на стандарте Unicode, взятая отсюда: http://semplicewebsites.com/removing-accents-javascript

var Latinise = {};Latinise.latin_map = {"Á":"A",
"Ă":"A",
"Ắ":"A",
"Ặ":"A",
"Ằ":"A",
"Ẳ":"A",
"Ẵ":"A",
"Ǎ":"A",
"Â":"A",
"Ấ":"A",
"Ậ":"A",
"Ầ":"A",
"Ẩ":"A",
"Ẫ":"A",
"Ä":"A",
"Ǟ":"A",
"Ȧ":"A",
"Ǡ":"A",
"Ạ":"A",
"Ȁ":"A",
"À":"A",
"Ả":"A",
"Ȃ":"A",
"Ā":"A",
"Ą":"A",
"Å":"A",
"Ǻ":"A",
"Ḁ":"A",
"Ⱥ":"A",
"Ã":"A",
"Ꜳ":"AA",
"Æ":"AE",
"Ǽ":"AE",
"Ǣ":"AE",
"Ꜵ":"AO",
"Ꜷ":"AU",
"Ꜹ":"AV",
"Ꜻ":"AV",
"Ꜽ":"AY",
"Ḃ":"B",
"Ḅ":"B",
"Ɓ":"B",
"Ḇ":"B",
"Ƀ":"B",
"Ƃ":"B",
"Ć":"C",
"Č":"C",
"Ç":"C",
"Ḉ":"C",
"Ĉ":"C",
"Ċ":"C",
"Ƈ":"C",
"Ȼ":"C",
"Ď":"D",
"Ḑ":"D",
"Ḓ":"D",
"Ḋ":"D",
"Ḍ":"D",
"Ɗ":"D",
"Ḏ":"D",
"Dz":"D",
"Dž":"D",
"Đ":"D",
"Ƌ":"D",
"DZ":"DZ",
"DŽ":"DZ",
"É":"E",
"Ĕ":"E",
"Ě":"E",
"Ȩ":"E",
"Ḝ":"E",
"Ê":"E",
"Ế":"E",
"Ệ":"E",
"Ề":"E",
"Ể":"E",
"Ễ":"E",
"Ḙ":"E",
"Ë":"E",
"Ė":"E",
"Ẹ":"E",
"Ȅ":"E",
"È":"E",
"Ẻ":"E",
"Ȇ":"E",
"Ē":"E",
"Ḗ":"E",
"Ḕ":"E",
"Ę":"E",
"Ɇ":"E",
"Ẽ":"E",
"Ḛ":"E",
"Ꝫ":"ET",
"Ḟ":"F",
"Ƒ":"F",
"Ǵ":"G",
"Ğ":"G",
"Ǧ":"G",
"Ģ":"G",
"Ĝ":"G",
"Ġ":"G",
"Ɠ":"G",
"Ḡ":"G",
"Ǥ":"G",
"Ḫ":"H",
"Ȟ":"H",
"Ḩ":"H",
"Ĥ":"H",
"Ⱨ":"H",
"Ḧ":"H",
"Ḣ":"H",
"Ḥ":"H",
"Ħ":"H",
"Í":"I",
"Ĭ":"I",
"Ǐ":"I",
"Î":"I",
"Ï":"I",
"Ḯ":"I",
"İ":"I",
"Ị":"I",
"Ȉ":"I",
"Ì":"I",
"Ỉ":"I",
"Ȋ":"I",
"Ī":"I",
"Į":"I",
"Ɨ":"I",
"Ĩ":"I",
"Ḭ":"I",
"Ꝺ":"D",
"Ꝼ":"F",
"Ᵹ":"G",
"Ꞃ":"R",
"Ꞅ":"S",
"Ꞇ":"T",
"Ꝭ":"IS",
"Ĵ":"J",
"Ɉ":"J",
"Ḱ":"K",
"Ǩ":"K",
"Ķ":"K",
"Ⱪ":"K",
"Ꝃ":"K",
"Ḳ":"K",
"Ƙ":"K",
"Ḵ":"K",
"Ꝁ":"K",
"Ꝅ":"K",
"Ĺ":"L",
"Ƚ":"L",
"Ľ":"L",
"Ļ":"L",
"Ḽ":"L",
"Ḷ":"L",
"Ḹ":"L",
"Ⱡ":"L",
"Ꝉ":"L",
"Ḻ":"L",
"Ŀ":"L",
"Ɫ":"L",
"Lj":"L",
"Ł":"L",
"LJ":"LJ",
"Ḿ":"M",
"Ṁ":"M",
"Ṃ":"M",
"Ɱ":"M",
"Ń":"N",
"Ň":"N",
"Ņ":"N",
"Ṋ":"N",
"Ṅ":"N",
"Ṇ":"N",
"Ǹ":"N",
"Ɲ":"N",
"Ṉ":"N",
"Ƞ":"N",
"Nj":"N",
"Ñ":"N",
"NJ":"NJ",
"Ó":"O",
"Ŏ":"O",
"Ǒ":"O",
"Ô":"O",
"Ố":"O",
"Ộ":"O",
"Ồ":"O",
"Ổ":"O",
"Ỗ":"O",
"Ö":"O",
"Ȫ":"O",
"Ȯ":"O",
"Ȱ":"O",
"Ọ":"O",
"Ő":"O",
"Ȍ":"O",
"Ò":"O",
"Ỏ":"O",
"Ơ":"O",
"Ớ":"O",
"Ợ":"O",
"Ờ":"O",
"Ở":"O",
"Ỡ":"O",
"Ȏ":"O",
"Ꝋ":"O",
"Ꝍ":"O",
"Ō":"O",
"Ṓ":"O",
"Ṑ":"O",
"Ɵ":"O",
"Ǫ":"O",
"Ǭ":"O",
"Ø":"O",
"Ǿ":"O",
"Õ":"O",
"Ṍ":"O",
"Ṏ":"O",
"Ȭ":"O",
"Ƣ":"OI",
"Ꝏ":"OO",
"Ɛ":"E",
"Ɔ":"O",
"Ȣ":"OU",
"Ṕ":"P",
"Ṗ":"P",
"Ꝓ":"P",
"Ƥ":"P",
"Ꝕ":"P",
"Ᵽ":"P",
"Ꝑ":"P",
"Ꝙ":"Q",
"Ꝗ":"Q",
"Ŕ":"R",
"Ř":"R",
"Ŗ":"R",
"Ṙ":"R",
"Ṛ":"R",
"Ṝ":"R",
"Ȑ":"R",
"Ȓ":"R",
"Ṟ":"R",
"Ɍ":"R",
"Ɽ":"R",
"Ꜿ":"C",
"Ǝ":"E",
"Ś":"S",
"Ṥ":"S",
"Š":"S",
"Ṧ":"S",
"Ş":"S",
"Ŝ":"S",
"Ș":"S",
"Ṡ":"S",
"Ṣ":"S",
"Ṩ":"S",
"Ť":"T",
"Ţ":"T",
"Ṱ":"T",
"Ț":"T",
"Ⱦ":"T",
"Ṫ":"T",
"Ṭ":"T",
"Ƭ":"T",
"Ṯ":"T",
"Ʈ":"T",
"Ŧ":"T",
"Ɐ":"A",
"Ꞁ":"L",
"Ɯ":"M",
"Ʌ":"V",
"Ꜩ":"TZ",
"Ú":"U",
"Ŭ":"U",
"Ǔ":"U",
"Û":"U",
"Ṷ":"U",
"Ü":"U",
"Ǘ":"U",
"Ǚ":"U",
"Ǜ":"U",
"Ǖ":"U",
"Ṳ":"U",
"Ụ":"U",
"Ű":"U",
"Ȕ":"U",
"Ù":"U",
"Ủ":"U",
"Ư":"U",
"Ứ":"U",
"Ự":"U",
"Ừ":"U",
"Ử":"U",
"Ữ":"U",
"Ȗ":"U",
"Ū":"U",
"Ṻ":"U",
"Ų":"U",
"Ů":"U",
"Ũ":"U",
"Ṹ":"U",
"Ṵ":"U",
"Ꝟ":"V",
"Ṿ":"V",
"Ʋ":"V",
"Ṽ":"V",
"Ꝡ":"VY",
"Ẃ":"W",
"Ŵ":"W",
"Ẅ":"W",
"Ẇ":"W",
"Ẉ":"W",
"Ẁ":"W",
"Ⱳ":"W",
"Ẍ":"X",
"Ẋ":"X",
"Ý":"Y",
"Ŷ":"Y",
"Ÿ":"Y",
"Ẏ":"Y",
"Ỵ":"Y",
"Ỳ":"Y",
"Ƴ":"Y",
"Ỷ":"Y",
"Ỿ":"Y",
"Ȳ":"Y",
"Ɏ":"Y",
"Ỹ":"Y",
"Ź":"Z",
"Ž":"Z",
"Ẑ":"Z",
"Ⱬ":"Z",
"Ż":"Z",
"Ẓ":"Z",
"Ȥ":"Z",
"Ẕ":"Z",
"Ƶ":"Z",
"IJ":"IJ",
"Œ":"OE",
"ᴀ":"A",
"ᴁ":"AE",
"ʙ":"B",
"ᴃ":"B",
"ᴄ":"C",
"ᴅ":"D",
"ᴇ":"E",
"ꜰ":"F",
"ɢ":"G",
"ʛ":"G",
"ʜ":"H",
"ɪ":"I",
"ʁ":"R",
"ᴊ":"J",
"ᴋ":"K",
"ʟ":"L",
"ᴌ":"L",
"ᴍ":"M",
"ɴ":"N",
"ᴏ":"O",
"ɶ":"OE",
"ᴐ":"O",
"ᴕ":"OU",
"ᴘ":"P",
"ʀ":"R",
"ᴎ":"N",
"ᴙ":"R",
"ꜱ":"S",
"ᴛ":"T",
"ⱻ":"E",
"ᴚ":"R",
"ᴜ":"U",
"ᴠ":"V",
"ᴡ":"W",
"ʏ":"Y",
"ᴢ":"Z",
"á":"a",
"ă":"a",
"ắ":"a",
"ặ":"a",
"ằ":"a",
"ẳ":"a",
"ẵ":"a",
"ǎ":"a",
"â":"a",
"ấ":"a",
"ậ":"a",
"ầ":"a",
"ẩ":"a",
"ẫ":"a",
"ä":"a",
"ǟ":"a",
"ȧ":"a",
"ǡ":"a",
"ạ":"a",
"ȁ":"a",
"à":"a",
"ả":"a",
"ȃ":"a",
"ā":"a",
"ą":"a",
"ᶏ":"a",
"ẚ":"a",
"å":"a",
"ǻ":"a",
"ḁ":"a",
"ⱥ":"a",
"ã":"a",
"ꜳ":"aa",
"æ":"ae",
"ǽ":"ae",
"ǣ":"ae",
"ꜵ":"ao",
"ꜷ":"au",
"ꜹ":"av",
"ꜻ":"av",
"ꜽ":"ay",
"ḃ":"b",
"ḅ":"b",
"ɓ":"b",
"ḇ":"b",
"ᵬ":"b",
"ᶀ":"b",
"ƀ":"b",
"ƃ":"b",
"ɵ":"o",
"ć":"c",
"č":"c",
"ç":"c",
"ḉ":"c",
"ĉ":"c",
"ɕ":"c",
"ċ":"c",
"ƈ":"c",
"ȼ":"c",
"ď":"d",
"ḑ":"d",
"ḓ":"d",
"ȡ":"d",
"ḋ":"d",
"ḍ":"d",
"ɗ":"d",
"ᶑ":"d",
"ḏ":"d",
"ᵭ":"d",
"ᶁ":"d",
"đ":"d",
"ɖ":"d",
"ƌ":"d",
"ı":"i",
"ȷ":"j",
"ɟ":"j",
"ʄ":"j",
"dz":"dz",
"dž":"dz",
"é":"e",
"ĕ":"e",
"ě":"e",
"ȩ":"e",
"ḝ":"e",
"ê":"e",
"ế":"e",
"ệ":"e",
"ề":"e",
"ể":"e",
"ễ":"e",
"ḙ":"e",
"ë":"e",
"ė":"e",
"ẹ":"e",
"ȅ":"e",
"è":"e",
"ẻ":"e",
"ȇ":"e",
"ē":"e",
"ḗ":"e",
"ḕ":"e",
"ⱸ":"e",
"ę":"e",
"ᶒ":"e",
"ɇ":"e",
"ẽ":"e",
"ḛ":"e",
"ꝫ":"et",
"ḟ":"f",
"ƒ":"f",
"ᵮ":"f",
"ᶂ":"f",
"ǵ":"g",
"ğ":"g",
"ǧ":"g",
"ģ":"g",
"ĝ":"g",
"ġ":"g",
"ɠ":"g",
"ḡ":"g",
"ᶃ":"g",
"ǥ":"g",
"ḫ":"h",
"ȟ":"h",
"ḩ":"h",
"ĥ":"h",
"ⱨ":"h",
"ḧ":"h",
"ḣ":"h",
"ḥ":"h",
"ɦ":"h",
"ẖ":"h",
"ħ":"h",
"ƕ":"hv",
"í":"i",
"ĭ":"i",
"ǐ":"i",
"î":"i",
"ï":"i",
"ḯ":"i",
"ị":"i",
"ȉ":"i",
"ì":"i",
"ỉ":"i",
"ȋ":"i",
"ī":"i",
"į":"i",
"ᶖ":"i",
"ɨ":"i",
"ĩ":"i",
"ḭ":"i",
"ꝺ":"d",
"ꝼ":"f",
"ᵹ":"g",
"ꞃ":"r",
"ꞅ":"s",
"ꞇ":"t",
"ꝭ":"is",
"ǰ":"j",
"ĵ":"j",
"ʝ":"j",
"ɉ":"j",
"ḱ":"k",
"ǩ":"k",
"ķ":"k",
"ⱪ":"k",
"ꝃ":"k",
"ḳ":"k",
"ƙ":"k",
"ḵ":"k",
"ᶄ":"k",
"ꝁ":"k",
"ꝅ":"k",
"ĺ":"l",
"ƚ":"l",
"ɬ":"l",
"ľ":"l",
"ļ":"l",
"ḽ":"l",
"ȴ":"l",
"ḷ":"l",
"ḹ":"l",
"ⱡ":"l",
"ꝉ":"l",
"ḻ":"l",
"ŀ":"l",
"ɫ":"l",
"ᶅ":"l",
"ɭ":"l",
"ł":"l",
"lj":"lj",
"ſ":"s",
"ẜ":"s",
"ẛ":"s",
"ẝ":"s",
"ḿ":"m",
"ṁ":"m",
"ṃ":"m",
"ɱ":"m",
"ᵯ":"m",
"ᶆ":"m",
"ń":"n",
"ň":"n",
"ņ":"n",
"ṋ":"n",
"ȵ":"n",
"ṅ":"n",
"ṇ":"n",
"ǹ":"n",
"ɲ":"n",
"ṉ":"n",
"ƞ":"n",
"ᵰ":"n",
"ᶇ":"n",
"ɳ":"n",
"ñ":"n",
"nj":"nj",
"ó":"o",
"ŏ":"o",
"ǒ":"o",
"ô":"o",
"ố":"o",
"ộ":"o",
"ồ":"o",
"ổ":"o",
"ỗ":"o",
"ö":"o",
"ȫ":"o",
"ȯ":"o",
"ȱ":"o",
"ọ":"o",
"ő":"o",
"ȍ":"o",
"ò":"o",
"ỏ":"o",
"ơ":"o",
"ớ":"o",
"ợ":"o",
"ờ":"o",
"ở":"o",
"ỡ":"o",
"ȏ":"o",
"ꝋ":"o",
"ꝍ":"o",
"ⱺ":"o",
"ō":"o",
"ṓ":"o",
"ṑ":"o",
"ǫ":"o",
"ǭ":"o",
"ø":"o",
"ǿ":"o",
"õ":"o",
"ṍ":"o",
"ṏ":"o",
"ȭ":"o",
"ƣ":"oi",
"ꝏ":"oo",
"ɛ":"e",
"ᶓ":"e",
"ɔ":"o",
"ᶗ":"o",
"ȣ":"ou",
"ṕ":"p",
"ṗ":"p",
"ꝓ":"p",
"ƥ":"p",
"ᵱ":"p",
"ᶈ":"p",
"ꝕ":"p",
"ᵽ":"p",
"ꝑ":"p",
"ꝙ":"q",
"ʠ":"q",
"ɋ":"q",
"ꝗ":"q",
"ŕ":"r",
"ř":"r",
"ŗ":"r",
"ṙ":"r",
"ṛ":"r",
"ṝ":"r",
"ȑ":"r",
"ɾ":"r",
"ᵳ":"r",
"ȓ":"r",
"ṟ":"r",
"ɼ":"r",
"ᵲ":"r",
"ᶉ":"r",
"ɍ":"r",
"ɽ":"r",
"ↄ":"c",
"ꜿ":"c",
"ɘ":"e",
"ɿ":"r",
"ś":"s",
"ṥ":"s",
"š":"s",
"ṧ":"s",
"ş":"s",
"ŝ":"s",
"ș":"s",
"ṡ":"s",
"ṣ":"s",
"ṩ":"s",
"ʂ":"s",
"ᵴ":"s",
"ᶊ":"s",
"ȿ":"s",
"ɡ":"g",
"ᴑ":"o",
"ᴓ":"o",
"ᴝ":"u",
"ť":"t",
"ţ":"t",
"ṱ":"t",
"ț":"t",
"ȶ":"t",
"ẗ":"t",
"ⱦ":"t",
"ṫ":"t",
"ṭ":"t",
"ƭ":"t",
"ṯ":"t",
"ᵵ":"t",
"ƫ":"t",
"ʈ":"t",
"ŧ":"t",
"ᵺ":"th",
"ɐ":"a",
"ᴂ":"ae",
"ǝ":"e",
"ᵷ":"g",
"ɥ":"h",
"ʮ":"h",
"ʯ":"h",
"ᴉ":"i",
"ʞ":"k",
"ꞁ":"l",
"ɯ":"m",
"ɰ":"m",
"ᴔ":"oe",
"ɹ":"r",
"ɻ":"r",
"ɺ":"r",
"ⱹ":"r",
"ʇ":"t",
"ʌ":"v",
"ʍ":"w",
"ʎ":"y",
"ꜩ":"tz",
"ú":"u",
"ŭ":"u",
"ǔ":"u",
"û":"u",
"ṷ":"u",
"ü":"u",
"ǘ":"u",
"ǚ":"u",
"ǜ":"u",
"ǖ":"u",
"ṳ":"u",
"ụ":"u",
"ű":"u",
"ȕ":"u",
"ù":"u",
"ủ":"u",
"ư":"u",
"ứ":"u",
"ự":"u",
"ừ":"u",
"ử":"u",
"ữ":"u",
"ȗ":"u",
"ū":"u",
"ṻ":"u",
"ų":"u",
"ᶙ":"u",
"ů":"u",
"ũ":"u",
"ṹ":"u",
"ṵ":"u",
"ᵫ":"ue",
"ꝸ":"um",
"ⱴ":"v",
"ꝟ":"v",
"ṿ":"v",
"ʋ":"v",
"ᶌ":"v",
"ⱱ":"v",
"ṽ":"v",
"ꝡ":"vy",
"ẃ":"w",
"ŵ":"w",
"ẅ":"w",
"ẇ":"w",
"ẉ":"w",
"ẁ":"w",
"ⱳ":"w",
"ẘ":"w",
"ẍ":"x",
"ẋ":"x",
"ᶍ":"x",
"ý":"y",
"ŷ":"y",
"ÿ":"y",
"ẏ":"y",
"ỵ":"y",
"ỳ":"y",
"ƴ":"y",
"ỷ":"y",
"ỿ":"y",
"ȳ":"y",
"ẙ":"y",
"ɏ":"y",
"ỹ":"y",
"ź":"z",
"ž":"z",
"ẑ":"z",
"ʑ":"z",
"ⱬ":"z",
"ż":"z",
"ẓ":"z",
"ȥ":"z",
"ẕ":"z",
"ᵶ":"z",
"ᶎ":"z",
"ʐ":"z",
"ƶ":"z",
"ɀ":"z",
"ff":"ff",
"ffi":"ffi",
"ffl":"ffl",
"fi":"fi",
"fl":"fl",
"ij":"ij",
"œ":"oe",
"st":"st",
"ₐ":"a",
"ₑ":"e",
"ᵢ":"i",
"ⱼ":"j",
"ₒ":"o",
"ᵣ":"r",
"ᵤ":"u",
"ᵥ":"v",
"ₓ":"x"};
String.prototype.latinise=function(){return this.replace(/[^A-Za-z0-9\[\] ]/g,function(a){return Latinise.latin_map[a]||a})};
String.prototype.latinize=String.prototype.latinise;
String.prototype.isLatin=function(){return this==this.latinise()}

Некоторые примеры:

> "Piqué".latinize();
"Pique"
> "Piqué".isLatin();
false
> "Pique".isLatin();
true
> "Piqué".latinise().isLatin();
true

Спасибо, это, безусловно, полезно. Есть место для оптимизации, но это хорошее начало. +1

Tomalak 12.03.2012 19:57

В чем смысл этой строки: String.prototype.latinize=String.prototype.latinise;?

zsitro 10.04.2013 12:44

@zsitro Эта строка позволяет вызывать функцию через "äöü".latinize() и "äöü".latinise(). Не очень хорошая практика !!

yckart 02.06.2013 00:45

Измените прототип строки, это основная плохая практика. Я должен его обновить. Спасибо, в любом случае

Totty.js 22.04.2015 16:40

Да - вы определенно можете избежать модификации прототипа - зависит от размера вашего проекта. Вы также можете выбрать предпочитаемое написание вместо того, чтобы раскрывать оба.

Ed. 15.01.2017 05:34

Если вы хотите добиться сортировки, где «ä» стоит после «a» и не рассматривается как одно и то же, вы можете использовать такую ​​функцию, как моя.

Вы всегда можете изменить алфавит, чтобы получить другую или даже странную сортировку. Однако, если вы хотите, чтобы некоторые буквы были эквивалентными, вам нужно манипулировать строками, например a = a.replace(/ä/, 'a') или аналогичными, как многие уже ответили выше. Я добавил прописные буквы, если кто-то хочет, чтобы все слова в верхнем регистре были перед всеми словами в нижнем регистре (тогда вы должны опустить .toLowerCase()).

function sortbyalphabet(a,b) {
        alphabet = "0123456789AaÀàÁáÂâÃãÄäBbCcÇçDdÈèÉéÊêËëFfGgHhÌìÍíÎîÏïJjKkLlMmNnÑñOoÒòÓóÔôÕõÖöPpQqRrSsTtÙùÚúÛûÜüVvWwXxÝýŸÿZz";
        a = a.toLowerCase();
        b = b.toLowerCase();
        shorterone = (a.length > b.length ? a : b);
        for (i=0; i<shorterone.length; i++){
            diff = alphabet.indexOf(a.charAt(i)) - alphabet.indexOf(b.charAt(i));
            if (diff!=0){
                return diff;
            }
        }
        // sort the shorter first
        return a.length - b.length;
    }
    var n = ["ast", "Äste", "apfel", "äpfel", "à"];
    console.info(n.sort(sortbyalphabet));
    // should return ["apfel", "ast", "à", "äpfel", "äste"]

Идея хорошая, реализацию можно улучшить. 1) Вы не использовали ключевое слово var. Это означает, что каждая объявленная вами переменная является глобальной. Это определенно не то, что вы имели в виду (в JS нет автоматической области видимости функций). Забывание var порождает неприятные ошибки. 2) Вы должны использовать замыкание вместо переопределения алфавита при каждом вызове функции. 3) Вы не выполняете ни проверку типов, ни строгие сравнения. - Я создал оптимизированную версию вашей функции здесь: jsperf.com/collation-string-sorting. И в Chrome, и в IE это примерно в 4 раза быстрее, чем ваш подход.

Tomalak 22.07.2012 14:26

Прямой перенос на javascript решения Кирона: https://github.com/rwarasaurus/nano/blob/master/system/helpers.php#L61-73:

/**
 * Normalise a string replacing foreign characters
 *
 * @param {String} str
 * @return {String} str
 */

var normalize = (function () {
    var a = ['À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï', 'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'ß', 'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'ÿ', 'Ā', 'ā', 'Ă', 'ă', 'Ą', 'ą', 'Ć', 'ć', 'Ĉ', 'ĉ', 'Ċ', 'ċ', 'Č', 'č', 'Ď', 'ď', 'Đ', 'đ', 'Ē', 'ē', 'Ĕ', 'ĕ', 'Ė', 'ė', 'Ę', 'ę', 'Ě', 'ě', 'Ĝ', 'ĝ', 'Ğ', 'ğ', 'Ġ', 'ġ', 'Ģ', 'ģ', 'Ĥ', 'ĥ', 'Ħ', 'ħ', 'Ĩ', 'ĩ', 'Ī', 'ī', 'Ĭ', 'ĭ', 'Į', 'į', 'İ', 'ı', 'IJ', 'ij', 'Ĵ', 'ĵ', 'Ķ', 'ķ', 'Ĺ', 'ĺ', 'Ļ', 'ļ', 'Ľ', 'ľ', 'Ŀ', 'ŀ', 'Ł', 'ł', 'Ń', 'ń', 'Ņ', 'ņ', 'Ň', 'ň', 'ʼn', 'Ō', 'ō', 'Ŏ', 'ŏ', 'Ő', 'ő', 'Œ', 'œ', 'Ŕ', 'ŕ', 'Ŗ', 'ŗ', 'Ř', 'ř', 'Ś', 'ś', 'Ŝ', 'ŝ', 'Ş', 'ş', 'Š', 'š', 'Ţ', 'ţ', 'Ť', 'ť', 'Ŧ', 'ŧ', 'Ũ', 'ũ', 'Ū', 'ū', 'Ŭ', 'ŭ', 'Ů', 'ů', 'Ű', 'ű', 'Ų', 'ų', 'Ŵ', 'ŵ', 'Ŷ', 'ŷ', 'Ÿ', 'Ź', 'ź', 'Ż', 'ż', 'Ž', 'ž', 'ſ', 'ƒ', 'Ơ', 'ơ', 'Ư', 'ư', 'Ǎ', 'ǎ', 'Ǐ', 'ǐ', 'Ǒ', 'ǒ', 'Ǔ', 'ǔ', 'Ǖ', 'ǖ', 'Ǘ', 'ǘ', 'Ǚ', 'ǚ', 'Ǜ', 'ǜ', 'Ǻ', 'ǻ', 'Ǽ', 'ǽ', 'Ǿ', 'ǿ'];
    var b = ['A', 'A', 'A', 'A', 'A', 'A', 'AE', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I', 'D', 'N', 'O', 'O', 'O', 'O', 'O', 'O', 'U', 'U', 'U', 'U', 'Y', 's', 'a', 'a', 'a', 'a', 'a', 'a', 'ae', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', 'n', 'o', 'o', 'o', 'o', 'o', 'o', 'u', 'u', 'u', 'u', 'y', 'y', 'A', 'a', 'A', 'a', 'A', 'a', 'C', 'c', 'C', 'c', 'C', 'c', 'C', 'c', 'D', 'd', 'D', 'd', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'G', 'g', 'G', 'g', 'G', 'g', 'G', 'g', 'H', 'h', 'H', 'h', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'IJ', 'ij', 'J', 'j', 'K', 'k', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l', 'l', 'l', 'N', 'n', 'N', 'n', 'N', 'n', 'n', 'O', 'o', 'O', 'o', 'O', 'o', 'OE', 'oe', 'R', 'r', 'R', 'r', 'R', 'r', 'S', 's', 'S', 's', 'S', 's', 'S', 's', 'T', 't', 'T', 't', 'T', 't', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'W', 'w', 'Y', 'y', 'Y', 'Z', 'z', 'Z', 'z', 'Z', 'z', 's', 'f', 'O', 'o', 'U', 'u', 'A', 'a', 'I', 'i', 'O', 'o', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'A', 'a', 'AE', 'ae', 'O', 'o'];

    return function (str) {
        var i = a.length;
        while (i--) str = str.replace(a[i], b[i]);
        return str;
    };
}());

И немного измененная версия, использующая char-map вместо двух массивов:

Чтобы сравнить эти два метода, я сделал простой тест: http://jsperf.com/replace-foreign-characters

/**
 * Normalise a string replacing foreign characters
 *
 * @param {String} str
 * @return {String}
 */
var normalize = (function () {
    var map = {
            "À": "A",
            "Á": "A",
            "Â": "A",
            "Ã": "A",
            "Ä": "A",
            "Å": "A",
            "Æ": "AE",
            "Ç": "C",
            "È": "E",
            "É": "E",
            "Ê": "E",
            "Ë": "E",
            "Ì": "I",
            "Í": "I",
            "Î": "I",
            "Ï": "I",
            "Ð": "D",
            "Ñ": "N",
            "Ò": "O",
            "Ó": "O",
            "Ô": "O",
            "Õ": "O",
            "Ö": "O",
            "Ø": "O",
            "Ù": "U",
            "Ú": "U",
            "Û": "U",
            "Ü": "U",
            "Ý": "Y",
            "ß": "s",
            "à": "a",
            "á": "a",
            "â": "a",
            "ã": "a",
            "ä": "a",
            "å": "a",
            "æ": "ae",
            "ç": "c",
            "è": "e",
            "é": "e",
            "ê": "e",
            "ë": "e",
            "ì": "i",
            "í": "i",
            "î": "i",
            "ï": "i",
            "ñ": "n",
            "ò": "o",
            "ó": "o",
            "ô": "o",
            "õ": "o",
            "ö": "o",
            "ø": "o",
            "ù": "u",
            "ú": "u",
            "û": "u",
            "ü": "u",
            "ý": "y",
            "ÿ": "y",
            "Ā": "A",
            "ā": "a",
            "Ă": "A",
            "ă": "a",
            "Ą": "A",
            "ą": "a",
            "Ć": "C",
            "ć": "c",
            "Ĉ": "C",
            "ĉ": "c",
            "Ċ": "C",
            "ċ": "c",
            "Č": "C",
            "č": "c",
            "Ď": "D",
            "ď": "d",
            "Đ": "D",
            "đ": "d",
            "Ē": "E",
            "ē": "e",
            "Ĕ": "E",
            "ĕ": "e",
            "Ė": "E",
            "ė": "e",
            "Ę": "E",
            "ę": "e",
            "Ě": "E",
            "ě": "e",
            "Ĝ": "G",
            "ĝ": "g",
            "Ğ": "G",
            "ğ": "g",
            "Ġ": "G",
            "ġ": "g",
            "Ģ": "G",
            "ģ": "g",
            "Ĥ": "H",
            "ĥ": "h",
            "Ħ": "H",
            "ħ": "h",
            "Ĩ": "I",
            "ĩ": "i",
            "Ī": "I",
            "ī": "i",
            "Ĭ": "I",
            "ĭ": "i",
            "Į": "I",
            "į": "i",
            "İ": "I",
            "ı": "i",
            "IJ": "IJ",
            "ij": "ij",
            "Ĵ": "J",
            "ĵ": "j",
            "Ķ": "K",
            "ķ": "k",
            "Ĺ": "L",
            "ĺ": "l",
            "Ļ": "L",
            "ļ": "l",
            "Ľ": "L",
            "ľ": "l",
            "Ŀ": "L",
            "ŀ": "l",
            "Ł": "l",
            "ł": "l",
            "Ń": "N",
            "ń": "n",
            "Ņ": "N",
            "ņ": "n",
            "Ň": "N",
            "ň": "n",
            "ʼn": "n",
            "Ō": "O",
            "ō": "o",
            "Ŏ": "O",
            "ŏ": "o",
            "Ő": "O",
            "ő": "o",
            "Œ": "OE",
            "œ": "oe",
            "Ŕ": "R",
            "ŕ": "r",
            "Ŗ": "R",
            "ŗ": "r",
            "Ř": "R",
            "ř": "r",
            "Ś": "S",
            "ś": "s",
            "Ŝ": "S",
            "ŝ": "s",
            "Ş": "S",
            "ş": "s",
            "Š": "S",
            "š": "s",
            "Ţ": "T",
            "ţ": "t",
            "Ť": "T",
            "ť": "t",
            "Ŧ": "T",
            "ŧ": "t",
            "Ũ": "U",
            "ũ": "u",
            "Ū": "U",
            "ū": "u",
            "Ŭ": "U",
            "ŭ": "u",
            "Ů": "U",
            "ů": "u",
            "Ű": "U",
            "ű": "u",
            "Ų": "U",
            "ų": "u",
            "Ŵ": "W",
            "ŵ": "w",
            "Ŷ": "Y",
            "ŷ": "y",
            "Ÿ": "Y",
            "Ź": "Z",
            "ź": "z",
            "Ż": "Z",
            "ż": "z",
            "Ž": "Z",
            "ž": "z",
            "ſ": "s",
            "ƒ": "f",
            "Ơ": "O",
            "ơ": "o",
            "Ư": "U",
            "ư": "u",
            "Ǎ": "A",
            "ǎ": "a",
            "Ǐ": "I",
            "ǐ": "i",
            "Ǒ": "O",
            "ǒ": "o",
            "Ǔ": "U",
            "ǔ": "u",
            "Ǖ": "U",
            "ǖ": "u",
            "Ǘ": "U",
            "ǘ": "u",
            "Ǚ": "U",
            "ǚ": "u",
            "Ǜ": "U",
            "ǜ": "u",
            "Ǻ": "A",
            "ǻ": "a",
            "Ǽ": "AE",
            "ǽ": "ae",
            "Ǿ": "O",
            "ǿ": "o"
        },
        nonWord = /\W/g,
        mapping = function (c) {
            return map[c] || c; 
        };


    return function (str) {
        return str.replace(nonWord, mapping);
    };
}());

Это строит карту персонажей с каждым вызовом replace(), именно этого я пытался избежать. Использование /\W/ - приятный штрих, даже если он попытается заменить все пробелы, цифры и знаки препинания.

Tomalak 02.06.2013 01:17

Первый вопрос легко решить, добавив карту и функцию замены к внешнему замыканию, что я только что сделал.

Tomalak 02.06.2013 01:36

... Я не понимаю вашу последнюю правку. Почему вы убрали функцию замены с крышки?

Tomalak 02.06.2013 06:08

@Tomalak Мне показалось, что функциональные выражения немного медленнее, чем прямые вызовы. Однако после небольшого исследования я пришел к выводу, что в данном случае это не имеет смысла. Теперь лучше?

yckart 02.06.2013 12:50

Да, теперь все в порядке. Сохраняете ли вы выражение функции в переменной и используете его (например, mapping) или передаете выражение функции в качестве аргумента (например, foo(function () {...}), как вы это делали в предыдущей версии), семантически не имеет значения. Последнее не является прямым вызовом, это просто выражение функции, которое никогда не сохраняется.

Tomalak 02.06.2013 13:19

Полное решение вашего запроса:

function convert_accented_characters(str){
    var conversions = new Object();
    conversions['ae'] = 'ä|æ|ǽ';
    conversions['oe'] = 'ö|œ';
    conversions['ue'] = 'ü';
    conversions['Ae'] = 'Ä';
    conversions['Ue'] = 'Ü';
    conversions['Oe'] = 'Ö';
    conversions['A'] = 'À|Á|Â|Ã|Ä|Å|Ǻ|Ā|Ă|Ą|Ǎ';
    conversions['a'] = 'à|á|â|ã|å|ǻ|ā|ă|ą|ǎ|ª';
    conversions['C'] = 'Ç|Ć|Ĉ|Ċ|Č';
    conversions['c'] = 'ç|ć|ĉ|ċ|č';
    conversions['D'] = 'Ð|Ď|Đ';
    conversions['d'] = 'ð|ď|đ';
    conversions['E'] = 'È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě';
    conversions['e'] = 'è|é|ê|ë|ē|ĕ|ė|ę|ě';
    conversions['G'] = 'Ĝ|Ğ|Ġ|Ģ';
    conversions['g'] = 'ĝ|ğ|ġ|ģ';
    conversions['H'] = 'Ĥ|Ħ';
    conversions['h'] = 'ĥ|ħ';
    conversions['I'] = 'Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ';
    conversions['i'] = 'ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı';
    conversions['J'] = 'Ĵ';
    conversions['j'] = 'ĵ';
    conversions['K'] = 'Ķ';
    conversions['k'] = 'ķ';
    conversions['L'] = 'Ĺ|Ļ|Ľ|Ŀ|Ł';
    conversions['l'] = 'ĺ|ļ|ľ|ŀ|ł';
    conversions['N'] = 'Ñ|Ń|Ņ|Ň';
    conversions['n'] = 'ñ|ń|ņ|ň|ʼn';
    conversions['O'] = 'Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ';
    conversions['o'] = 'ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º';
    conversions['R'] = 'Ŕ|Ŗ|Ř';
    conversions['r'] = 'ŕ|ŗ|ř';
    conversions['S'] = 'Ś|Ŝ|Ş|Š';
    conversions['s'] = 'ś|ŝ|ş|š|ſ';
    conversions['T'] = 'Ţ|Ť|Ŧ';
    conversions['t'] = 'ţ|ť|ŧ';
    conversions['U'] = 'Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ';
    conversions['u'] = 'ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ';
    conversions['Y'] = 'Ý|Ÿ|Ŷ';
    conversions['y'] = 'ý|ÿ|ŷ';
    conversions['W'] = 'Ŵ';
    conversions['w'] = 'ŵ';
    conversions['Z'] = 'Ź|Ż|Ž';
    conversions['z'] = 'ź|ż|ž';
    conversions['AE'] = 'Æ|Ǽ';
    conversions['ss'] = 'ß';
    conversions['IJ'] = 'IJ';
    conversions['ij'] = 'ij';
    conversions['OE'] = 'Œ';
    conversions['f'] = 'ƒ';
    for(var i in conversions){
        var re = new RegExp(conversions[i],"g");
        str = str.replace(re,i);
    }
    return str;
}

Правильная терминология для таких акцентов - Диакритики. После поиска этого термина в Google я нашел эта функция, который является частью backbone.paginator. Он имеет очень полную коллекцию диакритических знаков и заменяет их наиболее интуитивно понятным символом ascii. Я обнаружил, что это наиболее полное решение Javascript, доступное на сегодняшний день.

Полная функция для использования в будущем:

function removeDiacritics (str) {

  var defaultDiacriticsRemovalMap = [
    {'base':'A', 'letters':/[\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F]/g},
    {'base':'AA','letters':/[\uA732]/g},
    {'base':'AE','letters':/[\u00C6\u01FC\u01E2]/g},
    {'base':'AO','letters':/[\uA734]/g},
    {'base':'AU','letters':/[\uA736]/g},
    {'base':'AV','letters':/[\uA738\uA73A]/g},
    {'base':'AY','letters':/[\uA73C]/g},
    {'base':'B', 'letters':/[\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181]/g},
    {'base':'C', 'letters':/[\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E]/g},
    {'base':'D', 'letters':/[\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779]/g},
    {'base':'DZ','letters':/[\u01F1\u01C4]/g},
    {'base':'Dz','letters':/[\u01F2\u01C5]/g},
    {'base':'E', 'letters':/[\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E]/g},
    {'base':'F', 'letters':/[\u0046\u24BB\uFF26\u1E1E\u0191\uA77B]/g},
    {'base':'G', 'letters':/[\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E]/g},
    {'base':'H', 'letters':/[\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D]/g},
    {'base':'I', 'letters':/[\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197]/g},
    {'base':'J', 'letters':/[\u004A\u24BF\uFF2A\u0134\u0248]/g},
    {'base':'K', 'letters':/[\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2]/g},
    {'base':'L', 'letters':/[\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780]/g},
    {'base':'LJ','letters':/[\u01C7]/g},
    {'base':'Lj','letters':/[\u01C8]/g},
    {'base':'M', 'letters':/[\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C]/g},
    {'base':'N', 'letters':/[\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4]/g},
    {'base':'NJ','letters':/[\u01CA]/g},
    {'base':'Nj','letters':/[\u01CB]/g},
    {'base':'O', 'letters':/[\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C]/g},
    {'base':'OI','letters':/[\u01A2]/g},
    {'base':'OO','letters':/[\uA74E]/g},
    {'base':'OU','letters':/[\u0222]/g},
    {'base':'P', 'letters':/[\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754]/g},
    {'base':'Q', 'letters':/[\u0051\u24C6\uFF31\uA756\uA758\u024A]/g},
    {'base':'R', 'letters':/[\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782]/g},
    {'base':'S', 'letters':/[\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784]/g},
    {'base':'T', 'letters':/[\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786]/g},
    {'base':'TZ','letters':/[\uA728]/g},
    {'base':'U', 'letters':/[\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244]/g},
    {'base':'V', 'letters':/[\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245]/g},
    {'base':'VY','letters':/[\uA760]/g},
    {'base':'W', 'letters':/[\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72]/g},
    {'base':'X', 'letters':/[\u0058\u24CD\uFF38\u1E8A\u1E8C]/g},
    {'base':'Y', 'letters':/[\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE]/g},
    {'base':'Z', 'letters':/[\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762]/g},
    {'base':'a', 'letters':/[\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250]/g},
    {'base':'aa','letters':/[\uA733]/g},
    {'base':'ae','letters':/[\u00E6\u01FD\u01E3]/g},
    {'base':'ao','letters':/[\uA735]/g},
    {'base':'au','letters':/[\uA737]/g},
    {'base':'av','letters':/[\uA739\uA73B]/g},
    {'base':'ay','letters':/[\uA73D]/g},
    {'base':'b', 'letters':/[\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253]/g},
    {'base':'c', 'letters':/[\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184]/g},
    {'base':'d', 'letters':/[\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A]/g},
    {'base':'dz','letters':/[\u01F3\u01C6]/g},
    {'base':'e', 'letters':/[\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD]/g},
    {'base':'f', 'letters':/[\u0066\u24D5\uFF46\u1E1F\u0192\uA77C]/g},
    {'base':'g', 'letters':/[\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F]/g},
    {'base':'h', 'letters':/[\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265]/g},
    {'base':'hv','letters':/[\u0195]/g},
    {'base':'i', 'letters':/[\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131]/g},
    {'base':'j', 'letters':/[\u006A\u24D9\uFF4A\u0135\u01F0\u0249]/g},
    {'base':'k', 'letters':/[\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3]/g},
    {'base':'l', 'letters':/[\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747]/g},
    {'base':'lj','letters':/[\u01C9]/g},
    {'base':'m', 'letters':/[\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F]/g},
    {'base':'n', 'letters':/[\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5]/g},
    {'base':'nj','letters':/[\u01CC]/g},
    {'base':'o', 'letters':/[\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275]/g},
    {'base':'oi','letters':/[\u01A3]/g},
    {'base':'ou','letters':/[\u0223]/g},
    {'base':'oo','letters':/[\uA74F]/g},
    {'base':'p','letters':/[\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755]/g},
    {'base':'q','letters':/[\u0071\u24E0\uFF51\u024B\uA757\uA759]/g},
    {'base':'r','letters':/[\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783]/g},
    {'base':'s','letters':/[\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B]/g},
    {'base':'t','letters':/[\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787]/g},
    {'base':'tz','letters':/[\uA729]/g},
    {'base':'u','letters':/[\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289]/g},
    {'base':'v','letters':/[\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C]/g},
    {'base':'vy','letters':/[\uA761]/g},
    {'base':'w','letters':/[\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73]/g},
    {'base':'x','letters':/[\u0078\u24E7\uFF58\u1E8B\u1E8D]/g},
    {'base':'y','letters':/[\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF]/g},
    {'base':'z','letters':/[\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763]/g}
  ];

  for(var i=0; i<defaultDiacriticsRemovalMap.length; i++) {
    str = str.replace(defaultDiacriticsRemovalMap[i].letters, defaultDiacriticsRemovalMap[i].base);
  }

  return str;

}

Выглядит очень хорошо. - К сожалению, на момент написания этого вопроса backbone.js не существовало. :)

Tomalak 10.08.2013 13:50

больше обсуждения этого решения на stackoverflow.com/a/18391901/759452

Adrien Be 16.09.2014 18:52

Просто следует нормализовать цепочку и запустить замену кодами:

var str = "Letras Á É Í Ó Ú Ñ - á é í ó ú ñ...";
console.info (str.normalize ("NFKD").replace (/[\u0300-\u036F]/g, ""));
// Letras A E I O U N - a e i o u n...

См. нормализовать

Тогда вы можете использовать эту функцию:

function noTilde (s) {
    if (s.normalize != undefined) {
        s = s.normalize ("NFKD");
    }
    return s.replace (/[\u0300-\u036F]/g, "");
}

Это очень мило! Но с другой стороны, на момент написания он был передовым и вряд ли портативным.

Tomalak 21.05.2014 00:40

может быть инкапсулирован в функцию

atiruz 21.05.2014 00:58

Всякая инкапсуляция будет бесполезна, если движок JS в браузере не поддерживает эту функцию.

Tomalak 21.05.2014 02:32

На дворе 2016 год, а Safari все еще не поддерживает его ... Жаль, что было бы очень удобно иметь этот инструмент под рукой.

Chris Kobrzak 08.02.2016 19:00

Это не поддерживается в IE :(

beginning 24.02.2016 07:19

@beginning Вот библиотека, которую вы можете использовать в качестве полифилла, чтобы получить функцию нормализации в браузерах, у которых ее нет: github.com/walling/unorm Я знаю, что это 4 года спустя, ну да ладно.

ADJenks 23.09.2020 21:14

Просто попробуйте это со шведскими буквами åäö, и вы ошибочно получите aao. Не очень приятно ...

l33t 28.01.2021 02:35

Давным-давно я сделал это на Java и нашел другое решение, основанное на одной строке, которая захватывает часть таблицы Unicode, которая была важна для преобразования - остальное было преобразовано в? или любой другой заменяющий символ. Поэтому я попытался преобразовать его в JavaScript. Имейте в виду, что я не эксперт по JS. :-)

TAB_00C0 = "AAAAAAACEEEEIIII" +
    "DNOOOOO*OUUUUYIs" +
    "aaaaaaaceeeeiiii" +
    "?nooooo/ouuuuy?y" +
    "AaAaAaCcCcCcCcDd" +
    "DdEeEeEeEeEeGgGg" +
    "GgGgHhHhIiIiIiIi" +
    "IiJjJjKkkLlLlLlL" +
    "lLlNnNnNnnNnOoOo" +
    "OoOoRrRrRrSsSsSs" +
    "SsTtTtTtUuUuUuUu" +
    "UuUuWwYyYZzZzZzF";

function stripDiacritics(source) {
    var result = source.split('');
    for (var i = 0; i < result.length; i++) {
        var c = source.charCodeAt(i);
        if (c >= 0x00c0 && c <= 0x017f) {
            result[i] = String.fromCharCode(TAB_00C0.charCodeAt(c - 0x00c0));
        } else if (c > 127) {
            result[i] = '?';
        }
    }
    return result.join('');
}

stripDiacritics("Šupa, čo? ľšťčžýæøåℌð")

Это преобразует большинство символов Юникода latin1 + 2. Невозможно перевести один символ в несколько. Я не знаю его производительности на JS, в Java это, безусловно, самое быстрое из распространенных решений (6-50x), нет карты, нет регулярного выражения, ничего. Он производит строгий вывод в формате ASCII, потенциально с потерей информации, но размер вывода совпадает с размером ввода.

Я протестировал фрагмент с помощью http://www.webtoolkitonline.com/javascript-tester.html, и он произвел Supa, co? lstczyaoa??, как и ожидалось.

Это довольно здорово. Спасибо, что поделился!

Tomalak 17.08.2015 19:36

Недавно я сравнил это с "Šupa, čo? ľšťčžýæøåℌð".normalize ("NFKD").replace (/[\u0300-\u036F]/g, "") и был удивлен, что normalize + replace (регулярное выражение, заметьте) примерно в два раза быстрее! Я обвиняю эти вещи быть встроенные модули и массово оптимизированы, но это бесспорно. Другое дело, что это не совсем то же самое для некоторых персонажей. Результат: Supa, co? lstczyæøaHð - значит, æøð не разрешены, но, с другой стороны, он охватывает ℌð, который был вне диапазона моей таблицы. Зная это, честно говоря, я предпочитаю normalize+replace.

virgo47 12.08.2019 15:23

Основываясь на существующих ответах и ​​некоторых предложениях, я создал этот:

String.prototype.removeAccents = function() {

    var removalMap = {
        'A'  : /[AⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄ]/g,
        'AA' : /[Ꜳ]/g,
        'AE' : /[ÆǼǢ]/g,
        'AO' : /[Ꜵ]/g,
        'AU' : /[Ꜷ]/g,
        'AV' : /[ꜸꜺ]/g,
        'AY' : /[Ꜽ]/g,
        'B'  : /[BⒷBḂḄḆɃƂƁ]/g,
        'C'  : /[CⒸCĆĈĊČÇḈƇȻꜾ]/g,
        'D'  : /[DⒹDḊĎḌḐḒḎĐƋƊƉꝹ]/g,
        'DZ' : /[DZDŽ]/g,
        'Dz' : /[DzDž]/g,
        'E'  : /[EⒺEÈÉÊỀẾỄỂẼĒḔḖĔĖËẺĚȄȆẸỆȨḜĘḘḚƐƎ]/g,
        'F'  : /[FⒻFḞƑꝻ]/g,
        'G'  : /[GⒼGǴĜḠĞĠǦĢǤƓꞠꝽꝾ]/g,
        'H'  : /[HⒽHĤḢḦȞḤḨḪĦⱧⱵꞍ]/g,
        'I'  : /[IⒾIÌÍÎĨĪĬİÏḮỈǏȈȊỊĮḬƗ]/g,
        'J'  : /[JⒿJĴɈ]/g,
        'K'  : /[KⓀKḰǨḲĶḴƘⱩꝀꝂꝄꞢ]/g,
        'L'  : /[LⓁLĿĹĽḶḸĻḼḺŁȽⱢⱠꝈꝆꞀ]/g,
        'LJ' : /[LJ]/g,
        'Lj' : /[Lj]/g,
        'M'  : /[MⓂMḾṀṂⱮƜ]/g,
        'N'  : /[NⓃNǸŃÑṄŇṆŅṊṈȠƝꞐꞤ]/g,
        'NJ' : /[NJ]/g,
        'Nj' : /[Nj]/g,
        'O'  : /[OⓄOÒÓÔỒỐỖỔÕṌȬṎŌṐṒŎȮȰÖȪỎŐǑȌȎƠỜỚỠỞỢỌỘǪǬØǾƆƟꝊꝌ]/g,
        'OI' : /[Ƣ]/g,
        'OO' : /[Ꝏ]/g,
        'OU' : /[Ȣ]/g,
        'P'  : /[PⓅPṔṖƤⱣꝐꝒꝔ]/g,
        'Q'  : /[QⓆQꝖꝘɊ]/g,
        'R'  : /[RⓇRŔṘŘȐȒṚṜŖṞɌⱤꝚꞦꞂ]/g,
        'S'  : /[SⓈSẞŚṤŜṠŠṦṢṨȘŞⱾꞨꞄ]/g,
        'T'  : /[TⓉTṪŤṬȚŢṰṮŦƬƮȾꞆ]/g,
        'TZ' : /[Ꜩ]/g,
        'U'  : /[UⓊUÙÚÛŨṸŪṺŬÜǛǗǕǙỦŮŰǓȔȖƯỪỨỮỬỰỤṲŲṶṴɄ]/g,
        'V'  : /[VⓋVṼṾƲꝞɅ]/g,
        'VY' : /[Ꝡ]/g,
        'W'  : /[WⓌWẀẂŴẆẄẈⱲ]/g,
        'X'  : /[XⓍXẊẌ]/g,
        'Y'  : /[YⓎYỲÝŶỸȲẎŸỶỴƳɎỾ]/g,
        'Z'  : /[ZⓏZŹẐŻŽẒẔƵȤⱿⱫꝢ]/g,
        'a'  : /[aⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐ]/g,
        'aa' : /[ꜳ]/g,
        'ae' : /[æǽǣ]/g,
        'ao' : /[ꜵ]/g,
        'au' : /[ꜷ]/g,
        'av' : /[ꜹꜻ]/g,
        'ay' : /[ꜽ]/g,
        'b'  : /[bⓑbḃḅḇƀƃɓ]/g,
        'c'  : /[cⓒcćĉċčçḉƈȼꜿↄ]/g,
        'd'  : /[dⓓdḋďḍḑḓḏđƌɖɗꝺ]/g,
        'dz' : /[dzdž]/g,
        'e'  : /[eⓔeèéêềếễểẽēḕḗĕėëẻěȅȇẹệȩḝęḙḛɇɛǝ]/g,
        'f'  : /[fⓕfḟƒꝼ]/g,
        'g'  : /[gⓖgǵĝḡğġǧģǥɠꞡᵹꝿ]/g,
        'h'  : /[hⓗhĥḣḧȟḥḩḫẖħⱨⱶɥ]/g,
        'hv' : /[ƕ]/g,
        'i'  : /[iⓘiìíîĩīĭïḯỉǐȉȋịįḭɨı]/g,
        'j'  : /[jⓙjĵǰɉ]/g,
        'k'  : /[kⓚkḱǩḳķḵƙⱪꝁꝃꝅꞣ]/g,
        'l'  : /[lⓛlŀĺľḷḹļḽḻſłƚɫⱡꝉꞁꝇ]/g,
        'lj' : /[lj]/g,
        'm'  : /[mⓜmḿṁṃɱɯ]/g,
        'n'  : /[nⓝnǹńñṅňṇņṋṉƞɲʼnꞑꞥ]/g,
        'nj' : /[nj]/g,
        'o'  : /[oⓞoòóôồốỗổõṍȭṏōṑṓŏȯȱöȫỏőǒȍȏơờớỡởợọộǫǭøǿɔꝋꝍɵ]/g,
        'oi' : /[ƣ]/g,
        'ou' : /[ȣ]/g,
        'oo' : /[ꝏ]/g,
        'p'  : /[pⓟpṕṗƥᵽꝑꝓꝕ]/g,
        'q'  : /[qⓠqɋꝗꝙ]/g,
        'r'  : /[rⓡrŕṙřȑȓṛṝŗṟɍɽꝛꞧꞃ]/g,
        's'  : /[sⓢsßśṥŝṡšṧṣṩșşȿꞩꞅẛ]/g,
        't'  : /[tⓣtṫẗťṭțţṱṯŧƭʈⱦꞇ]/g,
        'tz' : /[ꜩ]/g,
        'u'  : /[uⓤuùúûũṹūṻŭüǜǘǖǚủůűǔȕȗưừứữửựụṳųṷṵʉ]/g,
        'v'  : /[vⓥvṽṿʋꝟʌ]/g,
        'vy' : /[ꝡ]/g,
        'w'  : /[wⓦwẁẃŵẇẅẘẉⱳ]/g,
        'x'  : /[xⓧxẋẍ]/g,
        'y'  : /[yⓨyỳýŷỹȳẏÿỷẙỵƴɏỿ]/g,
        'z'  : /[zⓩzźẑżžẓẕƶȥɀⱬꝣ]/g,
    };

    var str = this;

    for(var latin in removalMap) {
      var nonLatin = removalMap[latin];
      str = str.replace(nonLatin , latin);
    }

    return str;
}

Он использует настоящие символы вместо списка Unicode и хорошо работает.

Вы можете использовать это как

"ąąą".removeAccents(); // returns "aaa"

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

К сожалению, это сравнительно неэффективно с таким количеством регулярных выражений в цикле.

Tomalak 11.04.2016 10:57

Я решил по-другому, если хотите.

Здесь я использовал два массива, где searchChars, содержащий, который будет заменен, и replaceChars, содержащий желаемые символы.

var text = "your input string";
var searchChars = ['Å','Ä','å','Ö','ö']; // add more charecter.
var replaceChars = ['A','A','a','O','o']; // exact same index to searchChars.
var index;
for (var i = 0; i < text.length; i++) {
  if ( $.inArray(text[i], searchChars) >-1 ){ // $.inArray() is from jquery.
    index = searchChars.indexOf(text[i]);
    text = text.slice(0, i) + replaceChars[index] + text.slice(i+1,text.length);
  }
}

Это крайне неэффективно. Вам будет полезно выбрать одно из других решений.

Tomalak 30.12.2016 22:44

Простой и легкий способ:

function remove-accents(p){
c='áàãâäéèêëíìîïóòõôöúùûüçÁÀÃÂÄÉÈÊËÍÌÎÏÓÒÕÖÔÚÙÛÜÇ';s='aaaaaeeeeiiiiooooouuuucAAAAAEEEEIIIIOOOOOUUUUC';n='';for(i=0;i<p.length;i++){if (c.search(p.substr(i,1))>=0){n+=s.substr(c.search(p.substr(i,1)),1);} else{n+=p.substr(i,1);}} return n;
}

Итак, сделайте это:

remove-accents("Thís ís ân accêntéd phráse");

Выход:

"This is an accented phrase"

Ни в одном ответе не упоминается String.localeCompare, который делает именно то, что вы изначально хотели, но не то, о чем вы просите.

var list = ['a', 'b', 'c', 'o', 'u', 'z', 'ä', 'ö', 'ü'];

list.sort((a, b) => a.localeCompare(b));

console.info(list);

//Outputs ['a', 'ä', 'b', 'c', 'o', 'ö', 'u', 'ü', 'z']

Однако второй и третий параметры не поддерживаются старыми браузерами. Тем не менее, этот вариант стоит рассмотреть.

Хорошее дополнение! В этом конкретном случае я не влиял на как, строки сравнивались, так как это делается внутри TableSorter. Я мог влиять только на строки какие, которые хочу использовать. Поэтому заменить их на тот момент было единственным вариантом. Возможно, в более современных версиях TableSorter лучше внутренняя обработка этих вещей.

Tomalak 10.02.2017 19:08

Я добавил особое упоминание об этом ответе на вопрос.

Tomalak 10.02.2017 19:14

Если вы ищете специально способ преобразования символов с диакритическими знаками в символы без диакритических знаков, а не способ сортировки символов с диакритическими знаками, с небольшими изысками, можно управлять функцией String.localeCompare, чтобы найти основные латинские символы, которые соответствуют расширенные. Например, вы можете захотеть создать удобный для человека URL-адрес из заголовка страницы. Если да, вы можете сделать что-то вроде этого:

var baseChars = [];
for (var i = 97; i < 97 + 26; i++) {
  baseChars.push(String.fromCharCode(i));
}

//if needed, handle fancy compound characters
baseChars = baseChars.concat('ss,aa,ae,ao,au,av,ay,dz,hv,lj,nj,oi,ou,oo,tz,vy'.split(','));

function isUpperCase(c) { return c !== c.toLocaleLowerCase() }

function toBaseChar(c, opts) {
  opts = opts || {};
  //if (!('nonAlphaChar' in opts)) opts.nonAlphaChar = '';
  //if (!('noMatchChar' in opts)) opts.noMatchChar = '';
  if (!('locale' in opts)) opts.locale = 'en';

  var cOpts = {sensitivity: 'base'};

  //exit early for any non-alphabetical character
  if (c.localeCompare('9', opts.locale, cOpts) <= 0) return opts.nonAlphaChar === undefined ? c : opts.nonAlphaChar;

  for (var i = 0; i < baseChars.length; i++) {
    var baseChar = baseChars[i];

    var comp = c.localeCompare(baseChar, opts.locale, cOpts);
    if (comp == 0) return (isUpperCase(c)) ? baseChar.toUpperCase() : baseChar;
  }

  return opts.noMatchChar === undefined ? c : opts.noMatchChar;
}

function latinify(str, opts) {
  return str.replace(/[^\w\s\d]/g, function(c) {
    return toBaseChar(c, opts);
  })
}

// Example:
console.info(latinify('Čeština Tsėhesenėstsestotse Tshivenḓa Emigliàn–Rumagnòl Slovenščina Português Tiếng Việt Straße'))

// "Cestina Tsehesenestsestotse Tshivenda Emiglian–Rumagnol Slovenscina Portugues Tieng Viet Strasse"

Это должно работать достаточно хорошо, но если потребуется дальнейшая оптимизация, можно использовать двоичный поиск с localeCompare в качестве компаратора для поиска базового символа. Обратите внимание, что регистр сохраняется, а параметры позволяют сохранить, заменить или удалить символы, которые не являются алфавитными или не имеют соответствующих латинских символов, которыми они могут быть заменены. Эта реализация более быстрая и гибкая и должна работать с новыми символами по мере их добавления. Недостатком является то, что составные символы, такие как '', должны обрабатываться специально, если они нуждаются в поддержке.

Это очень мило. Жаль, что поздним ответам на старые темы уделяется так мало внимания.

Tomalak 23.02.2017 05:55

Самый лучший ответ здесь. Должен получить больше голосов (получил мое!)

Avrohom Yisroel 19.07.2017 20:46

Я просто хотел опубликовать свое решение, используя Строка # localeCompare

const base_chars = [
  '1', '2', '3', '4', '5', '6', '7', '8', '9',
  '0', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
  'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
  'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
  '-', '_', ' '
];
const fix = str => str.normalize('NFKD').split('')
    .map(c => base_chars.find(bc => bc.localeCompare(c, 'en', { sensitivity: 'base' })==0))
    .join('');

const str = 'OÒ óëå-123';
console.info(`fix(${str}) = ${fix(str)}`);

https://stackoverflow.com/a/37511463

With ES2015/ES6 String.Prototype.Normalize(),

const str = "Crème Brulée"
str.normalize('NFD').replace(/[\u0300-\u036f]/g, "")
> 'Creme Brulee'

Two things are happening here:

  1. normalize()ing to NFD Unicode normal form decomposes combined graphemes into the combination of simple ones. The è of Crème ends up expressed as e + ̀.
  2. Using a regex character class to match the U+0300 → U+036F range, it is now trivial to globally get rid of the diacritics, which the Unicode standard conveniently groups as the Combining Diacritical Marks Unicode block.

See comment for performance testing.

Alternatively, if you just want sorting

Intl.Collator has sufficient support ~85% right now, a polyfill is also available here but I haven't tested it.

const c = new Intl.Collator();
['creme brulee', 'crème brulée', 'crame brulai', 'crome brouillé',
'creme brulay', 'creme brulfé', 'creme bruléa'].sort(c.compare)
[ 'crame brulai','creme brulay','creme bruléa','creme brulee',
'crème brulée','creme brulfé','crome brouillé' ]


['creme brulee', 'crème brulée', 'crame brulai', 'crome brouillé'].sort((a,b) => a>b)
["crame brulai", "creme brulee", "crome brouillé", "crème brulée"]

Считаю этот ответ лучшим. Основан на стандарте Unicode и использует встроенные функции. Спасибо.

DavidC 03.09.2018 15:18
Intl.Collator(undefined , {sensitivity: 'base'})
oliversisson 16.10.2018 01:57

Я использовал это для создания заголовка, поэтому, прежде чем заменять пробелы на конечную косую черту и все на строчные буквы. Ваша функция работает отлично !!!

Simon Berton 21.02.2019 17:59

Уже обсуждался в другом ответе в этой ветке за 14 год. stackoverflow.com/a/23767389/18771

atiruz 14.11.2019 22:17

Это не правильно. Настоящий, ошибочно заменены недиакритические шведские / немецкие буквы. См. JSFiddle.

l33t 28.01.2021 02:32

Ответ os Crisalin почти идеален. Просто улучшили производительность, чтобы избежать создания нового RegExp при каждом запуске.

var normalizeConversions = [
    { regex: new RegExp('ä|æ|ǽ', 'g'), clean: 'ae' },
    { regex: new RegExp('ö|œ', 'g'), clean: 'oe' },
    { regex: new RegExp('ü', 'g'), clean: 'ue' },
    { regex: new RegExp('Ä', 'g'), clean: 'Ae' },
    { regex: new RegExp('Ü', 'g'), clean: 'Ue' },
    { regex: new RegExp('Ö', 'g'), clean: 'Oe' },
    { regex: new RegExp('À|Á|Â|Ã|Ä|Å|Ǻ|Ā|Ă|Ą|Ǎ', 'g'), clean: 'A' },
    { regex: new RegExp('à|á|â|ã|å|ǻ|ā|ă|ą|ǎ|ª', 'g'), clean: 'a' },
    { regex: new RegExp('Ç|Ć|Ĉ|Ċ|Č', 'g'), clean: 'C' },
    { regex: new RegExp('ç|ć|ĉ|ċ|č', 'g'), clean: 'c' },
    { regex: new RegExp('Ð|Ď|Đ', 'g'), clean: 'D' },
    { regex: new RegExp('ð|ď|đ', 'g'), clean: 'd' },
    { regex: new RegExp('È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě', 'g'), clean: 'E' },
    { regex: new RegExp('è|é|ê|ë|ē|ĕ|ė|ę|ě', 'g'), clean: 'e' },
    { regex: new RegExp('Ĝ|Ğ|Ġ|Ģ', 'g'), clean: 'G' },
    { regex: new RegExp('ĝ|ğ|ġ|ģ', 'g'), clean: 'g' },
    { regex: new RegExp('Ĥ|Ħ', 'g'), clean: 'H' },
    { regex: new RegExp('ĥ|ħ', 'g'), clean: 'h' },
    { regex: new RegExp('Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ', 'g'), clean: 'I' },
    { regex: new RegExp('ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı', 'g'), clean: 'i' },
    { regex: new RegExp('Ĵ', 'g'), clean: 'J' },
    { regex: new RegExp('ĵ', 'g'), clean: 'j' },
    { regex: new RegExp('Ķ', 'g'), clean: 'K' },
    { regex: new RegExp('ķ', 'g'), clean: 'k' },
    { regex: new RegExp('Ĺ|Ļ|Ľ|Ŀ|Ł', 'g'), clean: 'L' },
    { regex: new RegExp('ĺ|ļ|ľ|ŀ|ł', 'g'), clean: 'l' },
    { regex: new RegExp('Ñ|Ń|Ņ|Ň', 'g'), clean: 'N' },
    { regex: new RegExp('ñ|ń|ņ|ň|ʼn', 'g'), clean: 'n' },
    { regex: new RegExp('Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ', 'g'), clean: 'O' },
    { regex: new RegExp('ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º', 'g'), clean: 'o' },
    { regex: new RegExp('Ŕ|Ŗ|Ř', 'g'), clean: 'R' },
    { regex: new RegExp('ŕ|ŗ|ř', 'g'), clean: 'r' },
    { regex: new RegExp('Ś|Ŝ|Ş|Š', 'g'), clean: 'S' },
    { regex: new RegExp('ś|ŝ|ş|š|ſ', 'g'), clean: 's' },
    { regex: new RegExp('Ţ|Ť|Ŧ', 'g'), clean: 'T' },
    { regex: new RegExp('ţ|ť|ŧ', 'g'), clean: 't' },
    { regex: new RegExp('Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ', 'g'), clean: 'U' },
    { regex: new RegExp('ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ', 'g'), clean: 'u' },
    { regex: new RegExp('Ý|Ÿ|Ŷ', 'g'), clean: 'Y' },
    { regex: new RegExp('ý|ÿ|ŷ', 'g'), clean: 'y' },
    { regex: new RegExp('Ŵ', 'g'), clean: 'W' },
    { regex: new RegExp('ŵ', 'g'), clean: 'w' },
    { regex: new RegExp('Ź|Ż|Ž', 'g'), clean: 'Z' },
    { regex: new RegExp('ź|ż|ž', 'g'), clean: 'z' },
    { regex: new RegExp('Æ|Ǽ', 'g'), clean: 'AE' },
    { regex: new RegExp('ß', 'g'), clean: 'ss' },
    { regex: new RegExp('IJ', 'g'), clean: 'IJ' },
    { regex: new RegExp('ij', 'g'), clean: 'ij' },
    { regex: new RegExp('Œ', 'g'), clean: 'OE' },
    { regex: new RegExp('ƒ', 'g'), clean: 'f' }
];

Использование:

function(str){
    normalizeConversions.forEach(function(normalizeEntry){
        str = str.replace(normalizeEntry.regex, normalizeEntry.clean);
    });
    return str;
};

Я думаю, вы можете сэкономить место, используя литералы регулярных выражений, а классы символов более эффективны, чем чередования. Однако реальным ударом по производительности будет выполнение такого количества регулярных выражений в одной строке. Regex работает медленно. 100 регулярных выражений медленные * 100. Гораздо эффективнее выполнить одно регулярное выражение, которое соответствует 100 символам, и искать замены, как это делает принятый ответ, чем выполнять 100 регулярных выражений в цикле. Вдобавок к этому, строки JS неизменяемы, поэтому вы выделяете (количество регулярных выражений - 1) выбрасываемые строки с помощью этого подхода, что тоже довольно расточительно.

Tomalak 13.06.2018 17:08

Здесь есть 2 вещи: память и производительность обработки. Что касается использования памяти, вы правы, этот подход выделяет больше памяти, но сегодня все устройства имеют много памяти, и ее не так много памяти для выделения. Насчет производительности обработки, думаю, вы ошибаетесь. Я не подбираю 100 символов и ищу замену. Я делаю точно то же самое, что и ответ Crisalin, но вместо того, чтобы создавать RegExp при каждом приращении цикла, я создаю их один раз, повторно использую их при каждом вызове. Используйте немного больше памяти, но гораздо быстрее.

rmpt 13.06.2018 18:04

Вы применяете 100 (хорошо, сейчас 50) регулярных выражений в цикле, постоянно создавая новые строки в процессах. Это неэффективно. Попробуйте сами. Попробуйте также с длинными струнами.

Tomalak 13.06.2018 19:11

Я просто не понимаю, где у моего ответа худшее исполнение, чем у ответа Крисалина Петровского. Я делаю то же самое, но быстрее. Не говорю, что это лучшее, но это улучшение решения Crisalin, и это была единственная цель моего ответа.

rmpt 13.06.2018 19:15

Это могло быть. Я не сравниваю ваши подходы. Все, что я указываю в вашем подходе, применимо и к его. (Существует глобальный кеш для регулярных выражений, постоянное создание одних и тех же не влияет на производительность так сильно, как вы думаете.)

Tomalak 13.06.2018 19:19

Где спецификация этого глобального кеша регулярных выражений? Никогда ничего об этом не слышал. И, кстати, регулярные выражения не медленные, как вы могли подумать, на самом деле они очень быстрые, все зависит от того, как вы их пишете. Но в любом случае я просто улучшал ответ Crisalin, а не сравнивал его с принятым ответом.

rmpt 13.06.2018 19:51

Я не собираюсь с тобой спорить. Кэширование зависит от реализации, для этого в языке нет «спецификации». Не стесняйтесь взглянуть на то, что делает node.js (источник). Разумно предположить, что дорогостоящие операции, такие как создание объекта регулярного выражения, также кэшируются в большинстве других реализаций JS.

Tomalak 13.06.2018 20:34

Я не спорю с вами, я был искренне заинтересован и собирался удалить свой ответ, потому что, если то, что вы говорите, правда, ответ Crisalin имеет такую ​​же эффективность, что и мой. Но мы не можем запрограммировать предположения, поэтому я сохраню свой ответ.

rmpt 14.06.2018 12:39

Совершенно нормально. Я не пытался заставить вас удалить свой ответ.

Tomalak 14.06.2018 14:23

Я не могу придумать более простого способа эффективно удалить диакритические знаки все из строки, чем использование этого удивительное решение.

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

var string = "öäüÖÄÜ";

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

Уже обсуждался в другом ответе в этой теме. stackoverflow.com/a/23767389/18771

Tomalak 16.08.2018 13:46

@Tomalak Верно, я этого не заметил. В любом случае, я не удаляю свой ответ, потому что считаю, что лучше использовать «NFD» вместо «NFKD». Плюс у меня есть отрывок. :п

Takit Isy 17.08.2018 10:40

Для парней, использующих Машинопись, и тех, кто не хочет иметь дело с прототипами строк, вот машинописная версия Эд. Ответ:

    // Usage example:
    "Some string".replace(/[^a-zA-Z0-9-_]/g, char => ToLatinMap.get(char) || '')

    // Map:
    export let ToLatinMap: Map<string, string> = new Map<string, string>([
        ["Á", "A"],
        ["Ă", "A"],
        ["Ắ", "A"],
        ["Ặ", "A"],
        ["Ằ", "A"],
        ["Ẳ", "A"],
        ["Ẵ", "A"],
        ["Ǎ", "A"],
        ["Â", "A"],
        ["Ấ", "A"],
        ["Ậ", "A"],
        ["Ầ", "A"],
        ["Ẩ", "A"],
        ["Ẫ", "A"],
        ["Ä", "A"],
        ["Ǟ", "A"],
        ["Ȧ", "A"],
        ["Ǡ", "A"],
        ["Ạ", "A"],
        ["Ȁ", "A"],
        ["À", "A"],
        ["Ả", "A"],
        ["Ȃ", "A"],
        ["Ā", "A"],
        ["Ą", "A"],
        ["Å", "A"],
        ["Ǻ", "A"],
        ["Ḁ", "A"],
        ["Ⱥ", "A"],
        ["Ã", "A"],
        ["Ꜳ", "AA"],
        ["Æ", "AE"],
        ["Ǽ", "AE"],
        ["Ǣ", "AE"],
        ["Ꜵ", "AO"],
        ["Ꜷ", "AU"],
        ["Ꜹ", "AV"],
        ["Ꜻ", "AV"],
        ["Ꜽ", "AY"],
        ["Ḃ", "B"],
        ["Ḅ", "B"],
        ["Ɓ", "B"],
        ["Ḇ", "B"],
        ["Ƀ", "B"],
        ["Ƃ", "B"],
        ["Ć", "C"],
        ["Č", "C"],
        ["Ç", "C"],
        ["Ḉ", "C"],
        ["Ĉ", "C"],
        ["Ċ", "C"],
        ["Ƈ", "C"],
        ["Ȼ", "C"],
        ["Ď", "D"],
        ["Ḑ", "D"],
        ["Ḓ", "D"],
        ["Ḋ", "D"],
        ["Ḍ", "D"],
        ["Ɗ", "D"],
        ["Ḏ", "D"],
        ["Dz", "D"],
        ["Dž", "D"],
        ["Đ", "D"],
        ["Ƌ", "D"],
        ["DZ", "DZ"],
        ["DŽ", "DZ"],
        ["É", "E"],
        ["Ĕ", "E"],
        ["Ě", "E"],
        ["Ȩ", "E"],
        ["Ḝ", "E"],
        ["Ê", "E"],
        ["Ế", "E"],
        ["Ệ", "E"],
        ["Ề", "E"],
        ["Ể", "E"],
        ["Ễ", "E"],
        ["Ḙ", "E"],
        ["Ë", "E"],
        ["Ė", "E"],
        ["Ẹ", "E"],
        ["Ȅ", "E"],
        ["È", "E"],
        ["Ẻ", "E"],
        ["Ȇ", "E"],
        ["Ē", "E"],
        ["Ḗ", "E"],
        ["Ḕ", "E"],
        ["Ę", "E"],
        ["Ɇ", "E"],
        ["Ẽ", "E"],
        ["Ḛ", "E"],
        ["Ꝫ", "ET"],
        ["Ḟ", "F"],
        ["Ƒ", "F"],
        ["Ǵ", "G"],
        ["Ğ", "G"],
        ["Ǧ", "G"],
        ["Ģ", "G"],
        ["Ĝ", "G"],
        ["Ġ", "G"],
        ["Ɠ", "G"],
        ["Ḡ", "G"],
        ["Ǥ", "G"],
        ["Ḫ", "H"],
        ["Ȟ", "H"],
        ["Ḩ", "H"],
        ["Ĥ", "H"],
        ["Ⱨ", "H"],
        ["Ḧ", "H"],
        ["Ḣ", "H"],
        ["Ḥ", "H"],
        ["Ħ", "H"],
        ["Í", "I"],
        ["Ĭ", "I"],
        ["Ǐ", "I"],
        ["Î", "I"],
        ["Ï", "I"],
        ["Ḯ", "I"],
        ["İ", "I"],
        ["Ị", "I"],
        ["Ȉ", "I"],
        ["Ì", "I"],
        ["Ỉ", "I"],
        ["Ȋ", "I"],
        ["Ī", "I"],
        ["Į", "I"],
        ["Ɨ", "I"],
        ["Ĩ", "I"],
        ["Ḭ", "I"],
        ["Ꝺ", "D"],
        ["Ꝼ", "F"],
        ["Ᵹ", "G"],
        ["Ꞃ", "R"],
        ["Ꞅ", "S"],
        ["Ꞇ", "T"],
        ["Ꝭ", "IS"],
        ["Ĵ", "J"],
        ["Ɉ", "J"],
        ["Ḱ", "K"],
        ["Ǩ", "K"],
        ["Ķ", "K"],
        ["Ⱪ", "K"],
        ["Ꝃ", "K"],
        ["Ḳ", "K"],
        ["Ƙ", "K"],
        ["Ḵ", "K"],
        ["Ꝁ", "K"],
        ["Ꝅ", "K"],
        ["Ĺ", "L"],
        ["Ƚ", "L"],
        ["Ľ", "L"],
        ["Ļ", "L"],
        ["Ḽ", "L"],
        ["Ḷ", "L"],
        ["Ḹ", "L"],
        ["Ⱡ", "L"],
        ["Ꝉ", "L"],
        ["Ḻ", "L"],
        ["Ŀ", "L"],
        ["Ɫ", "L"],
        ["Lj", "L"],
        ["Ł", "L"],
        ["LJ", "LJ"],
        ["Ḿ", "M"],
        ["Ṁ", "M"],
        ["Ṃ", "M"],
        ["Ɱ", "M"],
        ["Ń", "N"],
        ["Ň", "N"],
        ["Ņ", "N"],
        ["Ṋ", "N"],
        ["Ṅ", "N"],
        ["Ṇ", "N"],
        ["Ǹ", "N"],
        ["Ɲ", "N"],
        ["Ṉ", "N"],
        ["Ƞ", "N"],
        ["Nj", "N"],
        ["Ñ", "N"],
        ["NJ", "NJ"],
        ["Ó", "O"],
        ["Ŏ", "O"],
        ["Ǒ", "O"],
        ["Ô", "O"],
        ["Ố", "O"],
        ["Ộ", "O"],
        ["Ồ", "O"],
        ["Ổ", "O"],
        ["Ỗ", "O"],
        ["Ö", "O"],
        ["Ȫ", "O"],
        ["Ȯ", "O"],
        ["Ȱ", "O"],
        ["Ọ", "O"],
        ["Ő", "O"],
        ["Ȍ", "O"],
        ["Ò", "O"],
        ["Ỏ", "O"],
        ["Ơ", "O"],
        ["Ớ", "O"],
        ["Ợ", "O"],
        ["Ờ", "O"],
        ["Ở", "O"],
        ["Ỡ", "O"],
        ["Ȏ", "O"],
        ["Ꝋ", "O"],
        ["Ꝍ", "O"],
        ["Ō", "O"],
        ["Ṓ", "O"],
        ["Ṑ", "O"],
        ["Ɵ", "O"],
        ["Ǫ", "O"],
        ["Ǭ", "O"],
        ["Ø", "O"],
        ["Ǿ", "O"],
        ["Õ", "O"],
        ["Ṍ", "O"],
        ["Ṏ", "O"],
        ["Ȭ", "O"],
        ["Ƣ", "OI"],
        ["Ꝏ", "OO"],
        ["Ɛ", "E"],
        ["Ɔ", "O"],
        ["Ȣ", "OU"],
        ["Ṕ", "P"],
        ["Ṗ", "P"],
        ["Ꝓ", "P"],
        ["Ƥ", "P"],
        ["Ꝕ", "P"],
        ["Ᵽ", "P"],
        ["Ꝑ", "P"],
        ["Ꝙ", "Q"],
        ["Ꝗ", "Q"],
        ["Ŕ", "R"],
        ["Ř", "R"],
        ["Ŗ", "R"],
        ["Ṙ", "R"],
        ["Ṛ", "R"],
        ["Ṝ", "R"],
        ["Ȑ", "R"],
        ["Ȓ", "R"],
        ["Ṟ", "R"],
        ["Ɍ", "R"],
        ["Ɽ", "R"],
        ["Ꜿ", "C"],
        ["Ǝ", "E"],
        ["Ś", "S"],
        ["Ṥ", "S"],
        ["Š", "S"],
        ["Ṧ", "S"],
        ["Ş", "S"],
        ["Ŝ", "S"],
        ["Ș", "S"],
        ["Ṡ", "S"],
        ["Ṣ", "S"],
        ["Ṩ", "S"],
        ["Ť", "T"],
        ["Ţ", "T"],
        ["Ṱ", "T"],
        ["Ț", "T"],
        ["Ⱦ", "T"],
        ["Ṫ", "T"],
        ["Ṭ", "T"],
        ["Ƭ", "T"],
        ["Ṯ", "T"],
        ["Ʈ", "T"],
        ["Ŧ", "T"],
        ["Ɐ", "A"],
        ["Ꞁ", "L"],
        ["Ɯ", "M"],
        ["Ʌ", "V"],
        ["Ꜩ", "TZ"],
        ["Ú", "U"],
        ["Ŭ", "U"],
        ["Ǔ", "U"],
        ["Û", "U"],
        ["Ṷ", "U"],
        ["Ü", "U"],
        ["Ǘ", "U"],
        ["Ǚ", "U"],
        ["Ǜ", "U"],
        ["Ǖ", "U"],
        ["Ṳ", "U"],
        ["Ụ", "U"],
        ["Ű", "U"],
        ["Ȕ", "U"],
        ["Ù", "U"],
        ["Ủ", "U"],
        ["Ư", "U"],
        ["Ứ", "U"],
        ["Ự", "U"],
        ["Ừ", "U"],
        ["Ử", "U"],
        ["Ữ", "U"],
        ["Ȗ", "U"],
        ["Ū", "U"],
        ["Ṻ", "U"],
        ["Ų", "U"],
        ["Ů", "U"],
        ["Ũ", "U"],
        ["Ṹ", "U"],
        ["Ṵ", "U"],
        ["Ꝟ", "V"],
        ["Ṿ", "V"],
        ["Ʋ", "V"],
        ["Ṽ", "V"],
        ["Ꝡ", "VY"],
        ["Ẃ", "W"],
        ["Ŵ", "W"],
        ["Ẅ", "W"],
        ["Ẇ", "W"],
        ["Ẉ", "W"],
        ["Ẁ", "W"],
        ["Ⱳ", "W"],
        ["Ẍ", "X"],
        ["Ẋ", "X"],
        ["Ý", "Y"],
        ["Ŷ", "Y"],
        ["Ÿ", "Y"],
        ["Ẏ", "Y"],
        ["Ỵ", "Y"],
        ["Ỳ", "Y"],
        ["Ƴ", "Y"],
        ["Ỷ", "Y"],
        ["Ỿ", "Y"],
        ["Ȳ", "Y"],
        ["Ɏ", "Y"],
        ["Ỹ", "Y"],
        ["Ź", "Z"],
        ["Ž", "Z"],
        ["Ẑ", "Z"],
        ["Ⱬ", "Z"],
        ["Ż", "Z"],
        ["Ẓ", "Z"],
        ["Ȥ", "Z"],
        ["Ẕ", "Z"],
        ["Ƶ", "Z"],
        ["IJ", "IJ"],
        ["Œ", "OE"],
        ["ᴀ", "A"],
        ["ᴁ", "AE"],
        ["ʙ", "B"],
        ["ᴃ", "B"],
        ["ᴄ", "C"],
        ["ᴅ", "D"],
        ["ᴇ", "E"],
        ["ꜰ", "F"],
        ["ɢ", "G"],
        ["ʛ", "G"],
        ["ʜ", "H"],
        ["ɪ", "I"],
        ["ʁ", "R"],
        ["ᴊ", "J"],
        ["ᴋ", "K"],
        ["ʟ", "L"],
        ["ᴌ", "L"],
        ["ᴍ", "M"],
        ["ɴ", "N"],
        ["ᴏ", "O"],
        ["ɶ", "OE"],
        ["ᴐ", "O"],
        ["ᴕ", "OU"],
        ["ᴘ", "P"],
        ["ʀ", "R"],
        ["ᴎ", "N"],
        ["ᴙ", "R"],
        ["ꜱ", "S"],
        ["ᴛ", "T"],
        ["ⱻ", "E"],
        ["ᴚ", "R"],
        ["ᴜ", "U"],
        ["ᴠ", "V"],
        ["ᴡ", "W"],
        ["ʏ", "Y"],
        ["ᴢ", "Z"],
        ["á", "a"],
        ["ă", "a"],
        ["ắ", "a"],
        ["ặ", "a"],
        ["ằ", "a"],
        ["ẳ", "a"],
        ["ẵ", "a"],
        ["ǎ", "a"],
        ["â", "a"],
        ["ấ", "a"],
        ["ậ", "a"],
        ["ầ", "a"],
        ["ẩ", "a"],
        ["ẫ", "a"],
        ["ä", "a"],
        ["ǟ", "a"],
        ["ȧ", "a"],
        ["ǡ", "a"],
        ["ạ", "a"],
        ["ȁ", "a"],
        ["à", "a"],
        ["ả", "a"],
        ["ȃ", "a"],
        ["ā", "a"],
        ["ą", "a"],
        ["ᶏ", "a"],
        ["ẚ", "a"],
        ["å", "a"],
        ["ǻ", "a"],
        ["ḁ", "a"],
        ["ⱥ", "a"],
        ["ã", "a"],
        ["ꜳ", "aa"],
        ["æ", "ae"],
        ["ǽ", "ae"],
        ["ǣ", "ae"],
        ["ꜵ", "ao"],
        ["ꜷ", "au"],
        ["ꜹ", "av"],
        ["ꜻ", "av"],
        ["ꜽ", "ay"],
        ["ḃ", "b"],
        ["ḅ", "b"],
        ["ɓ", "b"],
        ["ḇ", "b"],
        ["ᵬ", "b"],
        ["ᶀ", "b"],
        ["ƀ", "b"],
        ["ƃ", "b"],
        ["ɵ", "o"],
        ["ć", "c"],
        ["č", "c"],
        ["ç", "c"],
        ["ḉ", "c"],
        ["ĉ", "c"],
        ["ɕ", "c"],
        ["ċ", "c"],
        ["ƈ", "c"],
        ["ȼ", "c"],
        ["ď", "d"],
        ["ḑ", "d"],
        ["ḓ", "d"],
        ["ȡ", "d"],
        ["ḋ", "d"],
        ["ḍ", "d"],
        ["ɗ", "d"],
        ["ᶑ", "d"],
        ["ḏ", "d"],
        ["ᵭ", "d"],
        ["ᶁ", "d"],
        ["đ", "d"],
        ["ɖ", "d"],
        ["ƌ", "d"],
        ["ı", "i"],
        ["ȷ", "j"],
        ["ɟ", "j"],
        ["ʄ", "j"],
        ["dz", "dz"],
        ["dž", "dz"],
        ["é", "e"],
        ["ĕ", "e"],
        ["ě", "e"],
        ["ȩ", "e"],
        ["ḝ", "e"],
        ["ê", "e"],
        ["ế", "e"],
        ["ệ", "e"],
        ["ề", "e"],
        ["ể", "e"],
        ["ễ", "e"],
        ["ḙ", "e"],
        ["ë", "e"],
        ["ė", "e"],
        ["ẹ", "e"],
        ["ȅ", "e"],
        ["è", "e"],
        ["ẻ", "e"],
        ["ȇ", "e"],
        ["ē", "e"],
        ["ḗ", "e"],
        ["ḕ", "e"],
        ["ⱸ", "e"],
        ["ę", "e"],
        ["ᶒ", "e"],
        ["ɇ", "e"],
        ["ẽ", "e"],
        ["ḛ", "e"],
        ["ꝫ", "et"],
        ["ḟ", "f"],
        ["ƒ", "f"],
        ["ᵮ", "f"],
        ["ᶂ", "f"],
        ["ǵ", "g"],
        ["ğ", "g"],
        ["ǧ", "g"],
        ["ģ", "g"],
        ["ĝ", "g"],
        ["ġ", "g"],
        ["ɠ", "g"],
        ["ḡ", "g"],
        ["ᶃ", "g"],
        ["ǥ", "g"],
        ["ḫ", "h"],
        ["ȟ", "h"],
        ["ḩ", "h"],
        ["ĥ", "h"],
        ["ⱨ", "h"],
        ["ḧ", "h"],
        ["ḣ", "h"],
        ["ḥ", "h"],
        ["ɦ", "h"],
        ["ẖ", "h"],
        ["ħ", "h"],
        ["ƕ", "hv"],
        ["í", "i"],
        ["ĭ", "i"],
        ["ǐ", "i"],
        ["î", "i"],
        ["ï", "i"],
        ["ḯ", "i"],
        ["ị", "i"],
        ["ȉ", "i"],
        ["ì", "i"],
        ["ỉ", "i"],
        ["ȋ", "i"],
        ["ī", "i"],
        ["į", "i"],
        ["ᶖ", "i"],
        ["ɨ", "i"],
        ["ĩ", "i"],
        ["ḭ", "i"],
        ["ꝺ", "d"],
        ["ꝼ", "f"],
        ["ᵹ", "g"],
        ["ꞃ", "r"],
        ["ꞅ", "s"],
        ["ꞇ", "t"],
        ["ꝭ", "is"],
        ["ǰ", "j"],
        ["ĵ", "j"],
        ["ʝ", "j"],
        ["ɉ", "j"],
        ["ḱ", "k"],
        ["ǩ", "k"],
        ["ķ", "k"],
        ["ⱪ", "k"],
        ["ꝃ", "k"],
        ["ḳ", "k"],
        ["ƙ", "k"],
        ["ḵ", "k"],
        ["ᶄ", "k"],
        ["ꝁ", "k"],
        ["ꝅ", "k"],
        ["ĺ", "l"],
        ["ƚ", "l"],
        ["ɬ", "l"],
        ["ľ", "l"],
        ["ļ", "l"],
        ["ḽ", "l"],
        ["ȴ", "l"],
        ["ḷ", "l"],
        ["ḹ", "l"],
        ["ⱡ", "l"],
        ["ꝉ", "l"],
        ["ḻ", "l"],
        ["ŀ", "l"],
        ["ɫ", "l"],
        ["ᶅ", "l"],
        ["ɭ", "l"],
        ["ł", "l"],
        ["lj", "lj"],
        ["ſ", "s"],
        ["ẜ", "s"],
        ["ẛ", "s"],
        ["ẝ", "s"],
        ["ḿ", "m"],
        ["ṁ", "m"],
        ["ṃ", "m"],
        ["ɱ", "m"],
        ["ᵯ", "m"],
        ["ᶆ", "m"],
        ["ń", "n"],
        ["ň", "n"],
        ["ņ", "n"],
        ["ṋ", "n"],
        ["ȵ", "n"],
        ["ṅ", "n"],
        ["ṇ", "n"],
        ["ǹ", "n"],
        ["ɲ", "n"],
        ["ṉ", "n"],
        ["ƞ", "n"],
        ["ᵰ", "n"],
        ["ᶇ", "n"],
        ["ɳ", "n"],
        ["ñ", "n"],
        ["nj", "nj"],
        ["ó", "o"],
        ["ŏ", "o"],
        ["ǒ", "o"],
        ["ô", "o"],
        ["ố", "o"],
        ["ộ", "o"],
        ["ồ", "o"],
        ["ổ", "o"],
        ["ỗ", "o"],
        ["ö", "o"],
        ["ȫ", "o"],
        ["ȯ", "o"],
        ["ȱ", "o"],
        ["ọ", "o"],
        ["ő", "o"],
        ["ȍ", "o"],
        ["ò", "o"],
        ["ỏ", "o"],
        ["ơ", "o"],
        ["ớ", "o"],
        ["ợ", "o"],
        ["ờ", "o"],
        ["ở", "o"],
        ["ỡ", "o"],
        ["ȏ", "o"],
        ["ꝋ", "o"],
        ["ꝍ", "o"],
        ["ⱺ", "o"],
        ["ō", "o"],
        ["ṓ", "o"],
        ["ṑ", "o"],
        ["ǫ", "o"],
        ["ǭ", "o"],
        ["ø", "o"],
        ["ǿ", "o"],
        ["õ", "o"],
        ["ṍ", "o"],
        ["ṏ", "o"],
        ["ȭ", "o"],
        ["ƣ", "oi"],
        ["ꝏ", "oo"],
        ["ɛ", "e"],
        ["ᶓ", "e"],
        ["ɔ", "o"],
        ["ᶗ", "o"],
        ["ȣ", "ou"],
        ["ṕ", "p"],
        ["ṗ", "p"],
        ["ꝓ", "p"],
        ["ƥ", "p"],
        ["ᵱ", "p"],
        ["ᶈ", "p"],
        ["ꝕ", "p"],
        ["ᵽ", "p"],
        ["ꝑ", "p"],
        ["ꝙ", "q"],
        ["ʠ", "q"],
        ["ɋ", "q"],
        ["ꝗ", "q"],
        ["ŕ", "r"],
        ["ř", "r"],
        ["ŗ", "r"],
        ["ṙ", "r"],
        ["ṛ", "r"],
        ["ṝ", "r"],
        ["ȑ", "r"],
        ["ɾ", "r"],
        ["ᵳ", "r"],
        ["ȓ", "r"],
        ["ṟ", "r"],
        ["ɼ", "r"],
        ["ᵲ", "r"],
        ["ᶉ", "r"],
        ["ɍ", "r"],
        ["ɽ", "r"],
        ["ↄ", "c"],
        ["ꜿ", "c"],
        ["ɘ", "e"],
        ["ɿ", "r"],
        ["ś", "s"],
        ["ṥ", "s"],
        ["š", "s"],
        ["ṧ", "s"],
        ["ş", "s"],
        ["ŝ", "s"],
        ["ș", "s"],
        ["ṡ", "s"],
        ["ṣ", "s"],
        ["ṩ", "s"],
        ["ʂ", "s"],
        ["ᵴ", "s"],
        ["ᶊ", "s"],
        ["ȿ", "s"],
        ["ɡ", "g"],
        ["ᴑ", "o"],
        ["ᴓ", "o"],
        ["ᴝ", "u"],
        ["ť", "t"],
        ["ţ", "t"],
        ["ṱ", "t"],
        ["ț", "t"],
        ["ȶ", "t"],
        ["ẗ", "t"],
        ["ⱦ", "t"],
        ["ṫ", "t"],
        ["ṭ", "t"],
        ["ƭ", "t"],
        ["ṯ", "t"],
        ["ᵵ", "t"],
        ["ƫ", "t"],
        ["ʈ", "t"],
        ["ŧ", "t"],
        ["ᵺ", "th"],
        ["ɐ", "a"],
        ["ᴂ", "ae"],
        ["ǝ", "e"],
        ["ᵷ", "g"],
        ["ɥ", "h"],
        ["ʮ", "h"],
        ["ʯ", "h"],
        ["ᴉ", "i"],
        ["ʞ", "k"],
        ["ꞁ", "l"],
        ["ɯ", "m"],
        ["ɰ", "m"],
        ["ᴔ", "oe"],
        ["ɹ", "r"],
        ["ɻ", "r"],
        ["ɺ", "r"],
        ["ⱹ", "r"],
        ["ʇ", "t"],
        ["ʌ", "v"],
        ["ʍ", "w"],
        ["ʎ", "y"],
        ["ꜩ", "tz"],
        ["ú", "u"],
        ["ŭ", "u"],
        ["ǔ", "u"],
        ["û", "u"],
        ["ṷ", "u"],
        ["ü", "u"],
        ["ǘ", "u"],
        ["ǚ", "u"],
        ["ǜ", "u"],
        ["ǖ", "u"],
        ["ṳ", "u"],
        ["ụ", "u"],
        ["ű", "u"],
        ["ȕ", "u"],
        ["ù", "u"],
        ["ủ", "u"],
        ["ư", "u"],
        ["ứ", "u"],
        ["ự", "u"],
        ["ừ", "u"],
        ["ử", "u"],
        ["ữ", "u"],
        ["ȗ", "u"],
        ["ū", "u"],
        ["ṻ", "u"],
        ["ų", "u"],
        ["ᶙ", "u"],
        ["ů", "u"],
        ["ũ", "u"],
        ["ṹ", "u"],
        ["ṵ", "u"],
        ["ᵫ", "ue"],
        ["ꝸ", "um"],
        ["ⱴ", "v"],
        ["ꝟ", "v"],
        ["ṿ", "v"],
        ["ʋ", "v"],
        ["ᶌ", "v"],
        ["ⱱ", "v"],
        ["ṽ", "v"],
        ["ꝡ", "vy"],
        ["ẃ", "w"],
        ["ŵ", "w"],
        ["ẅ", "w"],
        ["ẇ", "w"],
        ["ẉ", "w"],
        ["ẁ", "w"],
        ["ⱳ", "w"],
        ["ẘ", "w"],
        ["ẍ", "x"],
        ["ẋ", "x"],
        ["ᶍ", "x"],
        ["ý", "y"],
        ["ŷ", "y"],
        ["ÿ", "y"],
        ["ẏ", "y"],
        ["ỵ", "y"],
        ["ỳ", "y"],
        ["ƴ", "y"],
        ["ỷ", "y"],
        ["ỿ", "y"],
        ["ȳ", "y"],
        ["ẙ", "y"],
        ["ɏ", "y"],
        ["ỹ", "y"],
        ["ź", "z"],
        ["ž", "z"],
        ["ẑ", "z"],
        ["ʑ", "z"],
        ["ⱬ", "z"],
        ["ż", "z"],
        ["ẓ", "z"],
        ["ȥ", "z"],
        ["ẕ", "z"],
        ["ᵶ", "z"],
        ["ᶎ", "z"],
        ["ʐ", "z"],
        ["ƶ", "z"],
        ["ɀ", "z"],
        ["ff", "ff"],
        ["ffi", "ffi"],
        ["ffl", "ffl"],
        ["fi", "fi"],
        ["fl", "fl"],
        ["ij", "ij"],
        ["œ", "oe"],
        ["st", "st"],
        ["ₐ", "a"],
        ["ₑ", "e"],
        ["ᵢ", "i"],
        ["ⱼ", "j"],
        ["ₒ", "o"],
        ["ᵣ", "r"],
        ["ᵤ", "u"],
        ["ᵥ", "v"],
        ["ₓ", "x"],
    ]);
«Как удалить все символы, которых нет в отображении» был не вопрос. Кроме того, к настоящему времени я, вероятно, использовал бы Intl.Collator для этой задачи - во время вопроса и в среде, которая мне была нужна, для этого не было возможности.
Tomalak 07.01.2019 17:09

Как бы вы использовали Intl.Collator для преобразования нелатинских букв в латинские «эквиваленты»?

eddyP23 07.01.2019 19:21

Я бы не стал. Первоначальный вопрос касался сортировка списка строк, правильно относящихся к определенному языку. В разных языках строки сортируются по-разному, но простые строки JS не обладают необходимыми знаниями, чтобы делать это правильно. Сопоставление символов с диакритическими знаками и форм без диакритических знаков является обходным решением. При наличии встроенной поддержки сопоставления сопоставление символов становится относительно бесполезной операцией, поскольку оно никогда не может обеспечить правильность и скорость сортировки на основе сопоставления.

Tomalak 07.01.2019 19:45

Другие вопросы по теме