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

Для реализации бедным человеком near-collation-correct, сортирующего на стороне клиента, мне нужна функция JavaScript, которая делает эффективную односимвольную замену в строке.

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

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

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

Другие языки имеют средства, чтобы сделать просто что: предоставления 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]; 
  }) );
}

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

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


Ответы ниже падения двух категорий:

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

108
задан Tomalak 24 July 2019 в 08:25
поделиться

2 ответа

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

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

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

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

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

Так, существует та опция.

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

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]; 
    }) );
  }
})();
35
ответ дан Jason Bunting 24 November 2019 в 03:28
поделиться

На основе решения Jason Bunting вот то, что я использую теперь.

Все это - для jQuery tablesorter плагин: Для (почти корректный) сортировка неанглийских таблиц с tablesorter плагином необходимо использовать пользовательское 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()
}); 
16
ответ дан Tomalak 24 November 2019 в 03:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: