Поиск без учета регистра с помощью фильтра jqGridToolbar не может найти специальный турецкий символ

У меня проблема при использовании jqGrid filterToolbar. Панель инструментов выполняет поиск, но не может найти символ, содержащий "ı". Например, я могу выполнить поиск по слову "yapi", но панель инструментов поиска не может найти "yapı".

jQuery("#grid-table").jqGrid('filterToolbar',
    { stringResult: false, searchOperators: false, defaultSearch: "cn" });

Кодировка моей страницы:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

и мой пост ajax здесь

$ .ajax ({type: "Post", url: "page / get.aspx, contentType:" application / json; charset = utf-8 ", dataType:" json ", data:" {} ", success: function () {//}, ошибка: function () {//}});


person Murat Furkan Sönmez    schedule 02.04.2015    source источник


Ответы (1)


Я уверен, что проблема в кодировке HTML-страницы, которую вы используете. Я попытался воспроизвести проблему и открыл старую демонстрацию, сохраненную в кодировке ANSI. После того, как я вставил тест yapı в данные и сохранил, я смог воспроизвести проблему, но проверка кода показывает, что строка yapı была сохранена как yapi из-за кодировки ANSI. Затем я открыл ту же демонстрацию с помощью Блокнота (я работаю на компьютере с Windows), повторил то же самое и использовал SaveAs, чтобы иметь возможность выбирать кодировку UTF-8. Теперь можно было увидеть действительно yapı строку, отображаемую в сетке вместо yapi раньше, и я мог успешно отфильтровать строку. Конечно, во время обоих экспериментов у меня было <meta charset="utf-8">.

Таким образом, вы должны убедиться, что не только <meta charset="utf-8"> существует в <head> вашей HTML-страницы, но и данные также находятся в кодировке UTF-8. В случае встроенных данных (как в моем эксперименте) файл необходимо сохранить в формате UTF-8.

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

Проблема была для меня совершенно новой, но в турецком языке есть два i: один с точкой больше i, а другой без точки ı. Оба i имеют соответствующие заглавные буквы I: İ и I. Вся информация не отличается от многих других языков. Основная проблема заключается в выборе представления Unicode для 4 символов: турецкие символы i и I используют те же коды, что и латинские символы: U+0069 и U+0049. На U+0131 и U+0130 будут отображаться только символы ı и İ (см. здесь ). Такое сопоставление делает невозможным реализацию сравнения без учета регистра или функций JavaScript .toUpperCase() и .toLowerCase(). Если входной текст содержит латинскую букву i, тогда функция .toUpperCase() должна преобразовать его в I, но это неверно для турецкого языка и вместо этого должно быть İ. Таким же образом .toLowerCase() должен выдать ı для турецкого текста и i для английского текста.

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

OK. А теперь вернемся к проблеме. Как реализовать поиск без учета регистра в турецких текстах? После изменения лицензионного соглашения на jqGrid в версии 4.7.1 я продолжаю разработку его бесплатной версии (по лицензии MIT и GPL v2) под названием free jqGrid. Я реализовал много новых функций в первом выпуске бесплатного jqGrid: версии 4.8. Функция «настраиваемой фильтрации», описанная в статья в вики может помочь в реализации.

На основе этой функции я создал следующую демонстрацию . В процессе реализации я исправил небольшие ошибки в коде бесплатного jqGrid. Поэтому в демонстрации я использую последние исходники с GitHub (http://rawgit.com/free-jqgrid/jqGrid/master/js/jquery.jqgrid.src.js) (прочтите wiki об URL-адресах).

Я использовал следующие параметры в jqGrid

ignoreCase: false,
customSortOperations: {
    teq: {
        operand: "==",
        text: "Turkish insensitive \"equal\"",
        filter: function (options) {
            var fieldData = String(options.item[options.cmName]).replace(/i/g,'İ').toUpperCase(),
                searchValue = options.searchValue.replace(/i/g,'İ').toUpperCase();
            return fieldData === searchValue;
        }
    },
    tne: {
        operand: "!=",
        text: "Turkish insensitive \"not equal\"",
        filter: function (options) {
            var fieldData = String(options.item[options.cmName]).replace(/i/g,'İ').toUpperCase(),
                searchValue = options.searchValue.replace(/i/g,'İ').toUpperCase();
            return fieldData !== searchValue;
        }
    },
    tbw: {
        operand: "^",
        text: "Turkish insensitive \"begins with\"",
        filter: function (options) {
            var fieldData = String(options.item[options.cmName]).replace(/i/g,'İ').toUpperCase(),
                searchValue = options.searchValue.replace(/i/g,'İ').toUpperCase();
            return fieldData.substr(0,searchValue.length) === searchValue;
        }
    },
    tbn: {
        operand: "!^",
        text: "Turkish insensitive \"does not begin with\"",
        filter: function (options) {
            var fieldData = String(options.item[options.cmName]).replace(/i/g,'İ').toUpperCase(),
                searchValue = options.searchValue.replace(/i/g,'İ').toUpperCase();
            return fieldData.substr(0,searchValue.length) !== searchValue;
        }
    },
    tew: {
        operand: "|",
        text: "Turkish insensitive \"end with\"",
        filter: function (options) {
            var fieldData = String(options.item[options.cmName]).replace(/i/g,'İ').toUpperCase(),
                searchValue = options.searchValue.replace(/i/g,'İ').toUpperCase(),
                searchLength = searchValue.length;

            return fieldData.substr(fieldData.length-searchLength,searchLength) === searchValue;
        }
    },
    ten: {
        operand: "!@",
        text: "Turkish insensitive \"does not end with\"",
        filter: function (options) {
            var fieldData = String(options.item[options.cmName]).replace(/i/g,'İ').toUpperCase(),
                searchValue = options.searchValue.replace(/i/g,'İ').toUpperCase(),
                searchLength = searchValue.length;

            return fieldData.substr(fieldData.length-searchLength,searchLength) !== searchValue;
        }
    },
    tcn: {
        operand: "~",
        text: "Turkish insensitive \"contains\"",
        filter: function (options) {
            var fieldData = String(options.item[options.cmName]).replace(/i/g,'İ').toUpperCase(),
                searchValue = options.searchValue.replace(/i/g,'İ').toUpperCase();
            return fieldData.indexOf(searchValue,0) >= 0;
        }
    },
    tnc: {
        operand: "!~",
        text: "Turkish insensitive \"does not contain\"",
        filter: function (options) {
            var fieldData = String(options.item[options.cmName]).replace(/i/g,'İ').toUpperCase(),
                searchValue = options.searchValue.replace(/i/g,'İ').toUpperCase();
            return fieldData.indexOf(searchValue,0) < 0;
        }
    }
}

Опция customSortOperations определяет новую пользовательскую операцию для сравнения турецких текстов без учета регистра. Чтобы использовать эту опцию, нужно просто указать операции в searchoptions для столбцов, содержащих турецкие тексты:

searchoptions: { sopt: ["tcn", "tnc", "teq", "tne", "tbw", "tbn", "tew", "ten"] }

В результате фильтрация использует "tcn" (Turkish insensitive "contains") в качестве операции фильтрации по умолчанию. Если один из них использует searchOperators: true параметр filterToolbar, тогда могут быть выбраны другие операции поиска. Я надеюсь, что все указанные выше операции пользовательского сравнения верны и могут быть использованы в турецких сетках.

ОБНОВЛЕНО 2: я нашел еще один интересный вариант реализации: метод localeCompare, который поддерживает параметры. Я тестировал это в Google Chrome

"i".localeCompare("İ", "tr", { sensitivity: "base" }) === 0
"i".localeCompare("I", "tr", { sensitivity: "base" }) === 1
"ı".localeCompare("I", "tr", { sensitivity: "base" }) === 0
"ı".localeCompare("İ", "tr", { sensitivity: "base" }) === -1

or

"i".localeCompare("İ", "tr", { sensitivity: "accent" }) === 0
"i".localeCompare("I", "tr", { sensitivity: "accent" }) === 1
"ı".localeCompare("I", "tr", { sensitivity: "accent" }) === 0
"ı".localeCompare("İ", "tr", { sensitivity: "accent" }) === -1

но те же тесты в IE11 не дали результата, в отличие от информация о совместимости браузеров. Все приведенные выше вызовы localeCompare возвращают 0 в IE11. Может случиться так, что можно использовать другое значение sensitivity для получения ожидаемых результатов. IE9 вместо этого возвращает 1 или -1 для вышеуказанных вызовов localeCompare. Я полагаю, что он учитывает только первый параметр и игнорирует "tr", { sensitivity: "base" } часть. Результаты в Chrome выглядят так

введите описание изображения здесь

Один и тот же результат в Firefox

введите описание изображения здесь

но не в IE11

введите описание изображения здесь

Еще один вариант - использовать класс ECMAScript Internationalization API. Intl.Collator (см. ecma-402 и здесь), например

new Intl.Collator("tr", { sensitivity: "base" }).compare("i", "İ")

например, но IE, кажется, не намного лучше в этом случае.

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

person Oleg    schedule 02.04.2015
comment
Большое спасибо @Oleg. - person Murat Furkan Sönmez; 07.04.2015