Проблема проверки JavaScript с международными символами

Мы используем отличный плагин проверки достоверности для jQuery здесь, в Stack Overflow, чтобы выполнить проверку на стороне клиента перед его отправкой на сервер.

Как правило, это хорошо работает, но у нас есть царапины.

В форме запроса/ответа для поля имени пользователя используется следующий метод валидатора (обратите внимание, что вы должны быть выведены из системы, чтобы увидеть это поле на веб-сайте, на каждом /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.");  

Теперь это регулярное выражение выглядит странно, но это довольно просто:

  • соответствует началу строки (^)
  • соответствует любому из них.
    • символ слова (\ w)
    • тире (-)
    • space (\ s)
    • digit (\ d)
    • символы сумасшедшего языка (àèìòù и т.д.)
  • теперь соответствует концу строки ($)

Да, мы столкнулись с проблемой Интернационализированные регулярные выражения. Определение JavaScript "символа слова" не включает в себя международные символы.. вообще.

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

Может содержать только A-Z, 0-9, пробелы и дефисы

.. подтверждение возврат!

Очевидно, что валидация работает для других частей регулярного выражения.. так.. что дает?

Другая странная часть заключается в том, что эта проверка работает в консоли JavaScript браузера, но не при выполнении как части нашего стандарта *.js.

/^ [\ w-\sÀÈÌÒÙàèìòùÁÉÍÓÚÝáéíóúýÂÊÎÔÛâêîôûÃÑÕãñõÄËÏÖÜäëïöüçÇßØøÅåÆæÞþÐð] + $/.test('ÓBill de hÓra') === true

Раньше мы сталкивались с некоторыми действительно странными проблемами международного характера в JavaScript-коде, что приводило к очень-очень неприятным взломам. Мы хотели бы понять, что происходит здесь и почему. Пожалуйста, просветите нас!

Ответы

Ответ 1

Я думаю, что методы проверки электронной почты и URL-адресов являются хорошей ссылкой здесь, например. метод электронной почты:

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

script для компиляции этого регулярного выражения.

Другими словами, замена вашего произвольного списка символов "сумасшедшей луны" на это может помочь:

[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]

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

Ответ 2

На самом деле это не ответ, но у меня нет еще 50 rep, чтобы добавить комментарий... Это может быть связано с проблемами кодирования.

Yea "ECMA не должен заботиться о кодировании..." blah blah, ну, если вы находитесь в firefox, перейдите в Просмотp > Кодировка символов > Западный (ISO-8859-1), тогда попробуйте использовать поле "Имя".

Он отлично работает для меня после изменения кодировки вручную (если остальной части страницы не нравится переключатель кодировки: P)

(в IE8 вы можете перейти к Page > Encoding > Western European (Windows), чтобы получить тот же эффект)

Ответ 3

Что такое кодировка символов JS файла?

Для XML QNames я использую этот RegExp:

/**
 * Definition of an XML Name
 */
var NameStartChar = "A-Za-z:_\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D"+
                    "\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF"+
                    "\uF900-\uFDCF\uFDF0-\uFFFD\u010000-\u0EFFFF";
var NameChar = NameStartChar+"\\-\\.0-9\u00B7\u0300-\u036F\u203F-\u2040";
var Name = "^["+NameStartChar+"]["+NameChar+"]*$";
RegExp (Name).test (value);

Он работает как шарм и с интернационализированными персонажами. Обратите внимание на экранирование. Из-за этого я могу ограничить JS файл только символами ASCII. Поэтому я не испытываю проблем при работе с кодировками ISO-8859 и UTF-8.

Это не более верно, если вы используете кодировки символов, где ASCII не является реальным подмножеством (например, в Азии UTF-16).

Приветствия,

Ответ 4

Международные символы, перечисленные, являются частью расширенного ASCII. добавленные вами, конечно, не являются.

Ответ 5

Увидев, что оператор работает в консоли, может ли это сделать так, чтобы ваши .js файлы были сохранены (т.е. ascii или UTF-8) и что браузер загружает их таким образом и в процессе переводит символы?

Ответ 6

Используйте что-то вроде Fiddler или Charles (а не панель Firebug Net или что-нибудь еще, что на самом деле в браузере), чтобы проверить, что на самом деле происходит через провод. Это почти наверняка проблема с кодировкой: либо файл был сохранен в наборе символов Microsoft и отправляется как UTF-8, либо, может быть, наоборот.

В случае JS RegExps вы можете, как указывает Boldewyn, избегать этих проблем, указав кодовую точку Unicode для символов, которые вы хотите, вне диапазона US-ASCII. Было бы также убедиться, что вы не смешиваете кодировки между местом сохранения файла и местом его обслуживания.

Ответ 7

Поздно к игре здесь, но я просто использовал это выражение, и мне показалось, что это хорошо работает для меня. Похоже, что он достаточно всеобъемлющий и относительно простой:

var re = /^[A-zÀ-ÿ\s\d-]*$/g; 
var str1 = 'casa-me,pois 99 estou farto! Eis a lista:uma;duas;três';
var str2 = 'casa-me pois 99 estou farto Eis a lista uma duas três';

alert(re.test(str1));
alert(re.test(str2));