2009-07-02 32 views
21

Chúng tôi sử dụng tuyệt đối validator plugin for jQuery tại đây trên Ngăn xếp ngăn xếp để thực hiện xác thực phía máy khách của đầu vào trước khi được gửi tới máy chủ.Vấn đề xác thực JavaScript với các ký tự quốc tế

Nó thường hoạt động tốt, tuy nhiên, điều này đã khiến chúng tôi gãi đầu.

Phương pháp validator sau được sử dụng trên hỏi hình thức/câu trả lời cho trường tên người dùng (lưu ý rằng bạn phải đăng xuất khỏi để xem lĩnh vực này trên trang web trực; nó trên mỗi /question trang và trang /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."); 

Bây giờ regex này có vẻ lạ, nhưng nó khá đơn giản:

  • trận đấu đầu của chuỗi (^)
  • trận đấu bất kỳ trong số này ..
    • nhân vật từ (\ w)
    • dấu gạch ngang (-)
    • không gian (\ s)
    • chữ số (\ d)
    • ký tự ngôn ngữ trăng điên (àèìòù vv)
  • tại phù hợp với sự kết thúc của chuỗi ($)

Có, chúng tôi chạy vào vấn đề Internationalized Regular Expressions. Định nghĩa của JavaScript về "ký tự từ" không bao gồm các ký tự quốc tế .. ở tất cả.

Đây là phần lạ: mặc dù chúng tôi đã gặp sự cố khi tự thêm tấn ký tự quốc tế hợp lệ vào regex, nó không hoạt động. Bạn không thể nhập các ký tự quốc tế vào hộp nhập liệu cho tên người dùng mà không nhận được ..

Chỉ có thể chứa A-Z, 0-9, khoảng trắng và dấu gạch ngang

.. xác nhận sự trở lại!

Rõ ràng xác thực làm việc cho các phần khác của regex .. do đó .. những gì cung cấp?

Phần lạ khác là xác thực này hoạt động trong bảng điều khiển JavaScript của trình duyệt nhưng không phải khi được thực hiện như một phần của tiêu chuẩn * .js của chúng tôi bao gồm.

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

Chúng tôi đã gặp phải một số vấn đề nhân vật quốc tế thực sự kỳ lạ trong Mã JavaScript trước đây, dẫn đến một số hack rất, rất khó chịu. Chúng tôi muốn hiểu những gì đang xảy ra ở đây và tại sao. Hãy khai sáng cho chúng tôi!

+0

này có thể là một vấn đề mã hóa ký tự? Tức là, một mặt trăng điên "Ä" đến từ người dùng không phải là "Ä" trong regex của bạn? – balpha

+0

Tôi không biết câu trả lời nhưng đó là cách hay để viết câu hỏi. –

+0

@Onorio Jeff luôn luôn ủng hộ những câu hỏi được viết tốt, vì vậy anh ấy cũng nên tự làm điều đó :-) Nhưng bạn chắc chắn đúng. – balpha

Trả lời

35

Tôi nghĩ rằng phương pháp xác thực email và url là một tham chiếu tốt ở đây, ví dụ: phương thức email:

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

The script to compile that regex.

Nói cách khác, thay thế danh sách tùy ý của bạn về "mặt trăng điên" nhân vật với điều này có thể giúp:

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

Về cơ bản điều này tránh được các vấn đề mã hóa ký tự bạn có ở nơi khác bằng cách thay thế các nhân vật nhu cầu mã hóa với tổng quát hơn các định nghĩa. Trong khi không nhất thiết phải dễ đọc hơn, cho đến nay nó ngắn hơn danh sách đầy đủ của bạn.

+0

Chỉ cần làm rõ lý do tại sao điều này làm việc . Nếu tệp .js của bạn được mã hóa bằng ký tự mã hóa, tất cả các ký tự bên trong biểu thức regex bên trong nó sẽ được biểu thị trên mã hóa đó, ngay cả khi trang web của bạn sử dụng mã hóa khác. Trong các dự án của tôi, tôi đơn giản mã hóa mọi thứ có thể chứa các chuỗi quốc tế trong UTF-8. Điều này bao gồm các tệp .js. Điều gì có thể xảy ra với Jeff là tệp .js của anh ta được mã hóa trong bộ ký tự và trang của anh ấy được phân tích cú pháp bằng một bộ ký tự khác, các yêu cầu/phản hồi HTTP của anh ấy có thể được mã hóa với bộ ký tự giống như trang. Điều này giải thích tại sao nó hoạt động trên trình gỡ lỗi. – Hoffmann

+0

Một điều khác, hãy thử cảnh báo ("quốc tế") nếu nó hiển thị đúng tệp javascript của bạn được mã hóa trong cùng một mã hóa như trang của bạn. Tuy nhiên, một giải pháp khác là chỉ cần bao gồm các javascripts của bạn với:

2

ký tự quốc tế được liệt kê là một phần của ASCII mở rộng.những cái được bạn thêm vào chắc chắn là không.

2

Xem như câu lệnh hoạt động trong bảng điều khiển, điều này có thể làm cách tệp .js của bạn được lưu (tức là ascii hoặc UTF-8) và trình duyệt đang tải chúng như vậy và trong quá trình dịch các ký tự?

+0

JS không biết bất cứ điều gì về UTF-8, ngay cả khi mã hóa được thiết lập như vậy. – dusoft

+0

Nhưng trình duyệt có hoạt động, phải không? Điều gì xảy ra nếu tệp được tải dưới dạng UTF-8 và công cụ JS của trình duyệt diễn giải các ký tự sai do trình duyệt tải tệp không chính xác? – Colin

+2

Vâng, trình duyệt quan tâm. Nếu bạn lưu một "Ä" là không phải Unicode, nó sẽ dẫn đến một luồng byte UTF-8 không hợp lệ. Vì vậy, nó không bao giờ có thể phù hợp với một dòng byte UTF-8 tương ứng với "Ä". – Boldewyn

3

Mã hóa ký tự của tệp JS là gì?

Đối QNames XML tôi sử dụng RegExp này:

/** 
* 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); 

Nó hoạt động như một nét duyên dáng cũng với các nhân vật được quốc tế hóa. Lưu ý thoát. Do đó tôi có thể hạn chế tệp JS thành chỉ ASCII ký tự. Vì vậy, tôi không gặp rắc rối khi giao dịch với bộ mã hóa ISO-8859 và UTF-8.

Điều này không còn đúng, nếu bạn sử dụng mã hóa ký tự trong đó ASCII không phải là tập hợp con thực (ví dụ: ở châu Á UTF-16).

Chúc mừng,

+0

Như tôi đã hiểu, các quy tắc trình xác thực nằm trong tệp JS bên ngoài. Sau đó, tôi đặt cược vào tập tin đó đang sai mã hóa (tức là, không phải UTF-8). – Boldewyn

+0

Tôi đang mở tệp trên đĩa trong Notepad2 và có vẻ chính xác - giống với những gì bạn thấy ở trên trong ANSI và khi tôi chuyển sang Unicode, mã hóa UTF-8, cũng giống hệt nhau. –

+0

Điều đó không thể. ANSI 'Ä' (== ISO-8859-1) có biểu diễn một byte 'C4', trong khi UTF-8 'Ä' trông trong trình chỉnh sửa hex như 'C3 84'. Ý bạn là gì với 'chuyển'? Có thực sự chuyển đổi giữa các mã hóa? – Boldewyn

13

Đây không thực sự là câu trả lời nhưng tôi chưa có đại diện 50 để thêm nhận xét ... Nó chắc chắn có thể được quy cho các vấn đề về mã hóa.

Yea "ECMA không nên quan tâm đến mã hóa ..." blah blah, tốt nếu bạn đang sử dụng firefox, hãy truy cập Chế độ xem> Mã hóa ký tự> Western (ISO-8859-1) rồi thử sử dụng Tên cánh đồng.

Nó hoạt động tốt đối với tôi sau khi thay đổi mã hóa bằng tay (cấp phần còn lại của trang không thích công tắc mã hóa,: P)

(trên IE8 bạn có thể vào trang > Encoding> Tây Âu (Windows) để có hiệu ứng tương tự)

+0

anh ấy đúng, điều này làm cho công việc Tên: xác thực hợp lệ (!) –

2

Sử dụng thứ gì đó như Fiddler hoặc Charles (không phải bảng điều khiển Net Firebug hoặc bất kỳ thứ gì khác thực sự nằm trong trình duyệt) để kiểm tra xem cái gì thực sự đang đi qua dây. Nó gần như chắc chắn là một vấn đề mã hóa: hoặc tập tin đã được lưu trong một số bộ ký tự của Microsoft và đang được gửi dưới dạng UTF-8, hoặc có thể là cách khác.

Trong trường hợp của JS RegExps bạn có thể, như Boldewyn chỉ ra, tránh những vấn đề này bằng cách xác định điểm mã Unicode cho các ký tự bạn muốn nằm ngoài phạm vi US-ASCII. Nó vẫn sẽ là tốt để chắc chắn rằng bạn không trộn lên mã hóa giữa nơi mà các tập tin được lưu và nơi mà nó được phục vụ, mặc dù.

+0

gzip qua dây, quá lúng túng để làm –

+0

Cả Fiddler và Charles có thể đối phó với điều đó. IIRC Fiddler (ít nhất là trong phiên bản 2) sẽ cung cấp cho bạn một nút trong khu vực xem Response để cho phép bạn xem nội dung được giải nén. – NickFitz

2

ĐẾN trò chơi ở đây, nhưng tôi chỉ sử dụng biểu thức này và nó có vẻ hoạt động tốt cho tôi.Có vẻ là khá toàn diện và tương đối đơn giản:

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

Các vấn đề liên quan