国际字符的JavaScript验证问题

Jef*_*ood 22 javascript validation jquery internationalization

我们在Stack Overflow上使用jQuery的优秀验证器插件在输入提交到服务器之前对输入进行客户端验证.

它通常运作良好,然而,这个让我们摸不着头脑.

在用户名字段的提问/答案表单上使用以下验证方法(请注意,您必须注销才能在实际站点上查看此字段;它位于每个/question页面和/ask页面上)

$.validator.addMethod("validUserName",
  function(value, element) {
  return this.optional(element) || 
  /^[\w\-\s\dÀÈÌÒÙàèìòùÁÉÍÓÚÝáéíóúýÂÊÎÔÛâêîôûÃÑÕãñõÄËÏÖÜäëïöüçÇߨøÅ寿ÞþÐð]+$/.test(value); },
  "Can only contain A-Z, 0-9, spaces, and hyphens.");  
Run Code Online (Sandbox Code Playgroud)

现在这个正则表达式看起来很奇怪,但它非常简单:

  • 匹配字符串的开头(^)
  • 匹配任何这些..
    • 字符(\ w)
    • 破折号( - )
    • 空间(\ s)
    • 数字(\ d)
    • 疯狂的月亮语言字符(àèìòù等)
  • 现在匹配字符串的结尾($)

是的,我们遇到了国际化正则表达式问题.JavaScript对"单词字符"的定义根本不包括国际字符.

这是一个奇怪的部分:尽管我们已经麻烦地手动将大量有效的国际字符添加到正则表达式,但它不起作用.如果没有获取用户名,则无法在输入框中输入这些国际字符.

只能包含AZ,0-9,空格和连字符

..验证回报!

显然验证工作正则表达式的其他部分 ..所以..怎么办?

另一个奇怪的部分是,此验证在浏览器的JavaScript控制台中有效,但在作为我们的标准*.js包含的一部分执行时则不行.

/ ^ [\ W- \sÀÈÌÒÙàèìòùÁÉÍÓÚÝáéíóúýÂÊÎÔÛâêîôûÃÑÕãñõÄËÏÖÜäëïöüçÇߨøÅ寿ÞþÐð] + $ /.测试( 'ÓBill日的Hora')===真

我们之前在JavaScript代码中遇到了一些非常奇怪的国际角色问题,导致一些非常非常讨厌的黑客攻击.我们想了解这里发生了什么,为什么.请指教!

Jör*_*rer 36

我认为电子邮件和网址验证方法在这里是一个很好的参考,例如.电子邮件方法:

email: function(value, element) {
    return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test(value);
},
Run Code Online (Sandbox Code Playgroud)

编译该正则表达式的脚本.

换句话说,用这个替换你的"疯狂月亮"字符的任意列表可能会有所帮助:

[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]
Run Code Online (Sandbox Code Playgroud)

基本上,这可以通过用更一般的定义替换needs-encoding字符来避免您在其他地方遇到的字符编码问题.虽然不一定更具可读性,但到目前为止它比您的完整列表更短.


小智 14

这不是一个真正的答案,但我没有50个代表尚未添加评论......它肯定会归因于编码问题.

是的,"ECMA不应该关心编码..."等等等等,如果您使用的是Firefox,请转到View> Character Encoding> Western(ISO-8859-1),然后尝试使用Name字段.

手动更改编码后,它对我来说很好(授予页面的其余部分不喜欢编码开关,:P)

(在IE8上,您可以转到页面>编码>西欧(Windows)以获得相同的效果)