jqGrid filterToolbar 不区分大小写的搜索找不到特殊的土耳其语字符
Case insensitive search by jqGrid filterToolbar can't find special Turkish character
我在使用 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 post 在这里
$.ajax({
类型:"Post",
url: "page/get.aspx,
内容类型:"application/json; charset=utf-8",
数据类型:"json",
数据: ”{}”,
成功:函数(){
//
},
错误:函数(){
//
}
});
我确定问题出在您使用的 HTML 页面的编码上。我试图重现该问题并打开一个以 ANSI 编码保存的旧演示。在数据中插入测试 yapı
并保存后,我可以重现问题,但代码验证显示字符串 yapı
被保存为 yapi
因为 ANSI 编码。然后我使用记事本打开相同的演示(我在 Windows 计算机上工作)重复相同的操作并使用 SaveAs 来选择 UTF-8 编码。现在可以看到真正的 yapı
字符串显示在网格中而不是之前的 yapi
并且我可以成功地过滤字符串。因为我在两个实验中都有 <meta charset="utf-8">
。
所以您应该验证不仅 <meta charset="utf-8">
存在于 HTML 页面的 <head>
中,而且数据也采用 UTF-8 编码。如果是嵌入数据(如我的实验),文件需要以 UTF-8 格式保存。
更新:评论中的讨论表明主要问题是土耳其文本的不区分大小写过滤。
这个问题对我来说绝对是新问题,但是土耳其语有 两个 i
:一个指向 i
和另一个 没有点ı
。 i
都有相应的大写 I
:İ
和 I
。所有信息与许多其他语言没有什么不同。主要问题在于选择 4 个字符的 Unicode 表示形式:土耳其字符 i
和 I
使用 与拉丁字符 相同的代码: U+0069
和 U+0049
。只有字符 ı
和 İ
将映射到 U+0131
和 U+0130
(请参阅 here)。这样的映射使得无法实现不区分大小写的比较或 JavaScript 函数 .toUpperCase()
和 .toLowerCase()
。如果输入文本包含拉丁字母 i
,那么函数 .toUpperCase()
应该将其转换为 I
,但对于土耳其语来说这是错误的,应该是 İ
。同样,.toLowerCase()
应该为土耳其语文本生成 ı
,为英语文本生成 i
。
因此第一个重要信息:在不了解输入语言的情况下,不可能实现不区分大小写的通用版本。
好的。现在回到问题。如何在土耳其语文本中实现不区分大小写的搜索?在更改了 4.7.1 版 jqGrid 的许可协议后,我继续以免费 jqGrid 的名义开发它的免费版本(在 MIT 和 GPL v2 许可下)。我在免费 jqGrid 的第一个版本:4.8 版中实现了许多新功能。 the wiki article 中描述的 "custom filtering" 功能可以帮助实施。
基于我创建的关于 URL 的 the following demo. I made some small bug fixes in the code of free jqGrid during the implementation. So I use the latest sources from GitHub (http://rawgit.com/free-jqgrid/jqGrid/master/js/jquery.jqgrid.src.js
) in the demo (read wiki 功能。
我在 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"
) 作为默认过滤操作。如果使用 filterToolbar
的 searchOperators: true
选项,则可以选择另一种搜索操作。希望以上的自定义比较操作都是正确的,可以在土耳其格子中使用。
更新 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
或
"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 中的相同测试失败,与 the information about the browser compatibility 相反。 localeCompare
returns 0
在IE11中的所有上述调用。可以使用 sensitivity
的另一个值来获得预期的结果。对于上述 localeCompare
调用,IE9 改为 returns 1 或 -1。我想它只考虑第一个参数并忽略 "tr", { sensitivity: "base" }
部分。 Chrome 中的结果看起来如此
一个在 Firefox 中有相同的结果
但在 IE11 中没有
另一种选择是使用 The ECMAScript Internationalization API class Intl.Collator (see ecma-402 and here),例如
new Intl.Collator("tr", { sensitivity: "base" }).compare("i", "İ")
比如,不过IE好像也好不了多少
无论如何,我认为可以通过包括浏览器检测部分来改进上述解决方案,该部分为比较的实现选择闭包,并稍后在 customSortOperations
中使用最佳实现。尽管如此,上面的代码还是可以安全运行的,但它可能不是那么优雅。
我在使用 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 post 在这里
$.ajax({ 类型:"Post", url: "page/get.aspx, 内容类型:"application/json; charset=utf-8", 数据类型:"json", 数据: ”{}”, 成功:函数(){ // }, 错误:函数(){ // } });
我确定问题出在您使用的 HTML 页面的编码上。我试图重现该问题并打开一个以 ANSI 编码保存的旧演示。在数据中插入测试 yapı
并保存后,我可以重现问题,但代码验证显示字符串 yapı
被保存为 yapi
因为 ANSI 编码。然后我使用记事本打开相同的演示(我在 Windows 计算机上工作)重复相同的操作并使用 SaveAs 来选择 UTF-8 编码。现在可以看到真正的 yapı
字符串显示在网格中而不是之前的 yapi
并且我可以成功地过滤字符串。因为我在两个实验中都有 <meta charset="utf-8">
。
所以您应该验证不仅 <meta charset="utf-8">
存在于 HTML 页面的 <head>
中,而且数据也采用 UTF-8 编码。如果是嵌入数据(如我的实验),文件需要以 UTF-8 格式保存。
更新:评论中的讨论表明主要问题是土耳其文本的不区分大小写过滤。
这个问题对我来说绝对是新问题,但是土耳其语有 两个 i
:一个指向 i
和另一个 没有点ı
。 i
都有相应的大写 I
:İ
和 I
。所有信息与许多其他语言没有什么不同。主要问题在于选择 4 个字符的 Unicode 表示形式:土耳其字符 i
和 I
使用 与拉丁字符 相同的代码: U+0069
和 U+0049
。只有字符 ı
和 İ
将映射到 U+0131
和 U+0130
(请参阅 here)。这样的映射使得无法实现不区分大小写的比较或 JavaScript 函数 .toUpperCase()
和 .toLowerCase()
。如果输入文本包含拉丁字母 i
,那么函数 .toUpperCase()
应该将其转换为 I
,但对于土耳其语来说这是错误的,应该是 İ
。同样,.toLowerCase()
应该为土耳其语文本生成 ı
,为英语文本生成 i
。
因此第一个重要信息:在不了解输入语言的情况下,不可能实现不区分大小写的通用版本。
好的。现在回到问题。如何在土耳其语文本中实现不区分大小写的搜索?在更改了 4.7.1 版 jqGrid 的许可协议后,我继续以免费 jqGrid 的名义开发它的免费版本(在 MIT 和 GPL v2 许可下)。我在免费 jqGrid 的第一个版本:4.8 版中实现了许多新功能。 the wiki article 中描述的 "custom filtering" 功能可以帮助实施。
基于我创建的关于 URL 的 the following demo. I made some small bug fixes in the code of free jqGrid during the implementation. So I use the latest sources from GitHub (http://rawgit.com/free-jqgrid/jqGrid/master/js/jquery.jqgrid.src.js
) in the demo (read wiki 功能。
我在 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"
) 作为默认过滤操作。如果使用 filterToolbar
的 searchOperators: true
选项,则可以选择另一种搜索操作。希望以上的自定义比较操作都是正确的,可以在土耳其格子中使用。
更新 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
或
"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 中的相同测试失败,与 the information about the browser compatibility 相反。 localeCompare
returns 0
在IE11中的所有上述调用。可以使用 sensitivity
的另一个值来获得预期的结果。对于上述 localeCompare
调用,IE9 改为 returns 1 或 -1。我想它只考虑第一个参数并忽略 "tr", { sensitivity: "base" }
部分。 Chrome 中的结果看起来如此
一个在 Firefox 中有相同的结果
但在 IE11 中没有
另一种选择是使用 The ECMAScript Internationalization API class Intl.Collator (see ecma-402 and here),例如
new Intl.Collator("tr", { sensitivity: "base" }).compare("i", "İ")
比如,不过IE好像也好不了多少
无论如何,我认为可以通过包括浏览器检测部分来改进上述解决方案,该部分为比较的实现选择闭包,并稍后在 customSortOperations
中使用最佳实现。尽管如此,上面的代码还是可以安全运行的,但它可能不是那么优雅。