Biểu thức chính quy cho số dấu phẩy động


115

Tôi có một nhiệm vụ để khớp các số dấu phẩy động. Tôi đã viết biểu thức chính quy sau cho nó:

[-+]?[0-9]*\.?[0-9]*

Tuy nhiên, nó trả về một lỗi:

Invalid escape sequence (valid ones are  \b  \t  \n  \f  \r  \"  \'  \\ )

Theo hiểu biết của tôi, chúng tôi cần sử dụng một ký tự thoát cho .cũng. Xin hãy sửa cho tôi nơi tôi sai.


10
Ngôn ngữ regex này được sử dụng trong?
CaffGeek

3
@JDB - Tại sao bạn lại cho 100 điểm cho một số / float regex? Tiêu chuẩn đã luôn luôn được (?:\d+(?:\.\d*)?|\.\d+)và đã được đăng quảng cáo infinitum trên SO ...


1
[-+]?([0-9]*[.])?[0-9]+([eE][-+]?\d+)?nếu bạn cũng muốn nắm bắt ký hiệu theo cấp số nhân, e, g, 3.023e-23
wcochran

Trong một số ngôn ngữ như Java hoặc C ++, dấu gạch chéo ngược phải được thoát ra. Vì vậy, để lấy regex "\.", Bạn sẽ sử dụng chuỗi "\\.". Python giải quyết vấn đề này bằng cách sử dụng các chuỗi thô.
HackerBoss

Câu trả lời:


258

TL; DR

Sử dụng [.]thay vì \.[0-9]thay vì \dđể tránh các sự cố thoát trong một số ngôn ngữ (như Java).

Cảm ơn người vô danh đã nhận ra điều này.

Một mẫu tương đối đơn giản để khớp số dấu phẩy động là

[+-]?([0-9]*[.])?[0-9]+

Điều này sẽ phù hợp với:

  • 123
  • 123.456
  • .456

Xem một ví dụ làm việc

Nếu bạn cũng muốn đối sánh 123.(dấu chấm không có phần thập phân), thì bạn sẽ cần một biểu thức dài hơn một chút:

[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)

Xem câu trả lời của pkeller để có lời giải thích đầy đủ hơn về mẫu này

Nếu bạn muốn bao gồm các số không phải số thập phân, chẳng hạn như hex và bát phân, hãy xem câu trả lời của tôi cho Làm cách nào để xác định xem một chuỗi có phải là số hay không? .

Nếu bạn muốn xác thực rằng đầu vào là một số (thay vì tìm một số trong đầu vào), thì bạn nên bao quanh mẫu bằng ^$, như sau:

^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)$

Biểu thức chính quy bất thường

"Cụm từ thông dụng", như được triển khai trong hầu hết các ngôn ngữ hiện đại, API, khuôn khổ, thư viện, v.v., dựa trên một khái niệm được phát triển trong lý thuyết ngôn ngữ chính thức . Tuy nhiên, các kỹ sư phần mềm đã thêm nhiều phần mở rộng đưa những triển khai này vượt xa định nghĩa chính thức. Vì vậy, trong khi hầu hết các công cụ biểu thức chính quy giống nhau, thực tế không có tiêu chuẩn nào. Vì lý do này, rất nhiều phụ thuộc vào ngôn ngữ, API, khuôn khổ hoặc thư viện bạn đang sử dụng.

(Ngẫu nhiên, để giúp giảm thiểu nhầm lẫn, nhiều người đã sử dụng " regex " hoặc " regexp " để mô tả các ngôn ngữ đối sánh nâng cao này. Xem Regex có giống Biểu thức chính quy không? Tại RexEgg.com để biết thêm thông tin.)

Điều đó nói rằng, hầu hết các công cụ regex (thực tế, tất cả chúng, theo như tôi biết) sẽ chấp nhận \.. Rất có thể, đã xảy ra sự cố khi thoát.

Rắc rối với việc chạy trốn

Một số ngôn ngữ có hỗ trợ sẵn cho regex, chẳng hạn như JavaScript . Đối với những ngôn ngữ không có, thoát có thể là một vấn đề.

Điều này là do về cơ bản bạn đang viết mã bằng một ngôn ngữ trong một ngôn ngữ. Java, ví dụ, sử dụng \như một ký tự thoát trong chuỗi của nó, vì vậy nếu bạn muốn đặt một ký tự dấu gạch chéo ngược theo nghĩa đen trong một chuỗi, bạn phải thoát nó:

// creates a single character string: "\"
String x = "\\";

Tuy nhiên, regexes cũng sử dụng \ký tự để thoát, vì vậy nếu bạn muốn khớp một ký \tự theo nghĩa đen , bạn phải thoát ký tự đó cho công cụ regexe và sau đó thoát lại cho Java:

// Creates a two-character string: "\\"
// When used as a regex pattern, will match a single character: "\"
String regexPattern = "\\\\";

Trong trường hợp của bạn, có thể bạn đã không thoát khỏi ký tự gạch chéo ngược trong ngôn ngữ bạn đang lập trình:

// will most likely result in an "Illegal escape character" error
String wrongPattern = "\.";
// will result in the string "\."
String correctPattern = "\\.";

Tất cả những điều này có thể rất khó hiểu. Nếu ngôn ngữ bạn đang làm việc hỗ trợ chuỗi thô , thì bạn nên sử dụng những ngôn ngữ đó để cắt giảm số lượng dấu gạch chéo ngược, nhưng không phải tất cả các ngôn ngữ đều làm được (đáng chú ý nhất là: Java). May mắn thay, có một giải pháp thay thế đôi khi sẽ hoạt động:

String correctPattern = "[.]";

Đối với một công cụ regex, \.[.]có nghĩa chính xác như vậy. Lưu ý rằng điều này không hoạt động trong mọi trường hợp, như dòng mới ( \\n), dấu ngoặc vuông mở ( \\[) và dấu gạch chéo ngược ( \\\\hoặc [\\]).

Lưu ý về Số phù hợp

(Gợi ý: Khó hơn bạn nghĩ)

Đối sánh một số là một trong những điều bạn nghĩ là khá dễ dàng với regex, nhưng thực ra nó khá phức tạp. Hãy xem xét cách tiếp cận của bạn, từng phần một:

[-+]?

Khớp một tùy chọn -hoặc+

[0-9]*

Khớp 0 hoặc nhiều chữ số liên tiếp

\.?

Khớp một tùy chọn .

[0-9]*

Khớp 0 hoặc nhiều chữ số liên tiếp

Đầu tiên, chúng ta có thể làm sạch biểu thức này một chút bằng cách sử dụng viết tắt lớp ký tự cho các chữ số (lưu ý rằng điều này cũng dễ gặp phải vấn đề thoát được đề cập ở trên):

[0-9] = \d

Tôi sẽ sử dụng \dbên dưới, nhưng hãy nhớ rằng nó có nghĩa tương tự như [0-9]. (Thực ra, trong một số công cụ \dsẽ khớp với các chữ số từ tất cả các tập lệnh, vì vậy nó sẽ khớp nhiều hơn [0-9]ý muốn, nhưng điều đó có lẽ không quan trọng trong trường hợp của bạn.)

Bây giờ, nếu bạn nhìn vào điều này một cách cẩn thận, bạn sẽ nhận ra rằng mọi phần nhỏ nhất của mẫu của bạn là tùy chọn . Mẫu này có thể khớp với một chuỗi có độ dài 0; một chuỗi chỉ bao gồm +hoặc -; hoặc, một chuỗi chỉ bao gồm a .. Đây có lẽ không phải là những gì bạn dự định.

Để khắc phục điều này, sẽ hữu ích khi bắt đầu bằng cách "neo" regex của bạn với chuỗi bắt buộc tối thiểu, có thể là một chữ số:

\d+

Bây giờ chúng tôi muốn thêm phần thập phân, nhưng nó không đi đến nơi bạn nghĩ có thể:

\d+\.?\d* /* This isn't quite correct. */

Điều này vẫn sẽ khớp với các giá trị như 123.. Tệ hơn nữa, nó có một chút gì đó xấu xa về nó. Khoảng thời gian là tùy chọn, có nghĩa là bạn có hai lớp lặp lại cạnh nhau ( \d+\d*). Điều này thực sự có thể nguy hiểm nếu được sử dụng sai cách, mở hệ thống của bạn trước các cuộc tấn công DoS.

Để khắc phục điều này, thay vì coi dấu chấm là tùy chọn, chúng ta cần xử lý nó theo yêu cầu (để tách các lớp ký tự lặp lại) và thay vào đó làm cho toàn bộ phần thập phân là tùy chọn:

\d+(\.\d+)? /* Better. But... */

Điều này trông tốt hơn bây giờ. Chúng tôi yêu cầu khoảng thời gian giữa dãy chữ số đầu tiên và dãy số thứ hai, nhưng có một lỗ hổng nghiêm trọng: chúng tôi không thể đối sánh .123vì chữ số hàng đầu hiện là bắt buộc.

Điều này thực sự khá dễ dàng để sửa chữa. Thay vì làm cho phần "thập phân" của số là tùy chọn, chúng ta cần xem nó như một chuỗi các ký tự: 1 hoặc nhiều số có thể được bắt đầu bởi một số .có thể được bắt đầu bằng 0 hoặc nhiều số:

(\d*\.)?\d+

Bây giờ chúng ta chỉ cần thêm dấu:

[+-]?(\d*\.)?\d+

Tất nhiên, những dấu gạch chéo đó khá khó chịu trong Java, vì vậy chúng ta có thể thay thế trong các lớp ký tự dạng dài của mình:

[+-]?([0-9]*[.])?[0-9]+

Đối sánh so với Xác thực

Điều này đã xuất hiện trong các bình luận một vài lần, vì vậy tôi đang thêm một phụ lục về việc so khớp và xác thực.

Mục tiêu của việc đối sánh là tìm một số nội dung trong đầu vào ("cái kim trong bọc hay"). Mục tiêu của việc xác thực là để đảm bảo rằng đầu vào có định dạng mong đợi.

Regexes, về bản chất, chỉ khớp với văn bản. Với một số đầu vào, họ sẽ tìm thấy một số văn bản phù hợp hoặc sẽ không. Tuy nhiên, bằng cách "gắn" một biểu thức vào đầu và cuối của đầu vào bằng các thẻ liên kết ( ^$), chúng tôi có thể đảm bảo rằng không tìm thấy kết quả khớp nào trừ khi toàn bộ đầu vào khớp với biểu thức, sử dụng hiệu quả regex để xác thực .

Regex được mô tả ở trên ( [+-]?([0-9]*[.])?[0-9]+) sẽ khớp với một hoặc nhiều số trong một chuỗi mục tiêu. Vì vậy, với đầu vào:

apple 1.34 pear 7.98 version 1.2.3.4

Regex sẽ phù hợp 1.34, 7.98, 1.2, .3.4.

Để xác thực rằng một đầu vào nhất định là một số và không có gì khác ngoài một số, hãy "gắn" biểu thức vào đầu và cuối của đầu vào bằng cách gói nó trong các thẻ liên kết:

^[+-]?([0-9]*[.])?[0-9]+$

Thao tác này sẽ chỉ tìm thấy kết quả phù hợp nếu toàn bộ dữ liệu đầu vào là một số dấu phẩy động và sẽ không tìm thấy kết quả phù hợp nếu đầu vào chứa các ký tự bổ sung. Vì vậy, với đầu vào 1.2, một kết quả phù hợp sẽ được tìm thấy, nhưng apple 1.2 pearkhông tìm thấy kết quả phù hợp nào.

Lưu ý rằng một số công cụ regex có một validate, isMatchhoặc chức năng tương tự, trong đó chủ yếu làm những gì tôi đã mô tả tự động, trở về truenếu kết hợp được tìm thấy và falsenếu không phù hợp được tìm thấy. Cũng nên nhớ rằng một số công cụ cho phép bạn đặt các cờ thay đổi định nghĩa của ^$, khớp với đầu / cuối của một dòng chứ không phải là đầu / cuối của toàn bộ đầu vào. Đây thường không phải là mặc định, nhưng hãy đề phòng những cờ này.


2
JDB, cảm ơn và tôi hy vọng bạn vẫn ở bên cạnh! Tôi sẽ đọc bài đăng của bạn trong tương lai :) Câu trả lời của bạn chắc chắn quan tâm đến 0,24 và 2,2 và chính xác là không cho phép 4.2.44 Tất cả đã được thử nghiệm với regex101.com Tuy nhiên, nó không cho phép 123 mà như bạn nói có thể chấp nhận được (và tôi nghĩ nó Là!). Tôi có thể sửa lỗi này bằng cách thay đổi biểu thức của bạn thành [- +]? (\ D * [.])? \ D * (thông báo * ở cuối thay vì +) nhưng sau đó những thứ điên rồ như. (ví dụ thứ hai của bạn) được phép. Dù sao để có bánh của tôi và ăn nó quá?
Dave

2
@Dave -\d+(\.\d*)?|\.\d+
JDB vẫn nhớ Monica

/[-+]?(\d*[.])?\d+/.test("1.bc") // returns true
yeouuu

1
@yeouuu vâng, vì 1.khớp. Thêm ^$vào đầu và cuối của regex nếu bạn muốn chỉ khớp khi toàn bộ dữ liệu đầu vào khớp.
JDB vẫn nhớ Monica

5
float có thể có số mũ hoặc là NaN / Inf, vì vậy tôi sẽ sử dụng cái này [-+]?(([0-9]*[.]?[0-9]+([ed][-+]?[0-9]+)?)|(inf)|(nan)):, e / d cho float / double precision. Đừng quên một trường hợp cờ lần để regex
Markus Schmassmann

23

Tôi không nghĩ rằng bất kỳ câu trả lời nào trên trang này tại thời điểm viết bài là đúng (nhiều câu trả lời khác trên SO cũng sai). Điều phức tạp là bạn phải kết hợp tất cả các khả năng sau:

  • Không có dấu thập phân (tức là giá trị số nguyên)
  • Chữ số cả trước và sau dấu thập phân (ví dụ 0.35, 22.165)
  • Chữ số trước dấu thập phân chỉ (ví dụ 0., 1234.)
  • Chữ số sau dấu thập phân chỉ (ví dụ .0, .5678)

Đồng thời, bạn phải đảm bảo rằng có ít nhất một chữ số ở đâu đó, tức là những điều sau đây không được phép:

  • một dấu thập phân của chính nó
  • một dấu thập phân có dấu không có chữ số (tức là +.hoặc -.)
  • +hoặc -của riêng họ
  • một chuỗi trống

Điều này thoạt nghe có vẻ phức tạp, nhưng một cách để tìm cảm hứng là xem nguồn OpenJDK để biết java.lang.Double.valueOf(String)phương pháp này (bắt đầu tại http://hg.openjdk.java.net/jdk8/jdk8/jdk , nhấp vào "duyệt", điều hướng xuống /src/share/classes/java/lang/và tìm Doublelớp). Regex dài mà lớp này chứa đựng phục vụ cho nhiều khả năng khác nhau mà OP có thể không nghĩ đến, nhưng bỏ qua để đơn giản hóa các phần của nó liên quan đến NaN, vô cực, ký hiệu Thập lục phân và số mũ, và sử dụng \dthay vì ký hiệu POSIX cho một chữ số duy nhất, tôi có thể giảm các phần quan trọng của regex cho một số dấu phẩy động có dấu mà không có số mũ thành:

[+-]?((\d+\.?\d*)|(\.\d+))

Tôi không nghĩ rằng có một cách nào đó để tránh việc (...)|(...)xây dựng mà không cho phép thứ gì đó không chứa chữ số hoặc cấm một trong những khả năng không có chữ số trước dấu thập phân hoặc không có chữ số nào sau nó.

Rõ ràng trong thực tế, bạn sẽ cần phải phục vụ cho khoảng trắng sau hoặc trước, trong chính regex hoặc trong mã sử dụng nó.


Nếu bạn thêm yêu cầu khớp với các số như 123., thì có ... hoặc chuyển đổi là giải pháp duy nhất, như tôi đã chỉ ra trong một nhận xét về bài đăng ban đầu của tôi.
JDB vẫn nhớ Monica

1
Điều này và tất cả / hầu hết các câu trả lời khác, bỏ qua rằng một float có thể có một số mũ.
NateS

1
@NateS Đúng vậy, tôi đã viết "bỏ qua để đơn giản hóa các phần liên quan đến NaN, vô cực, ký hiệu thập lục phân và số mũ", bởi vì điều đó có vẻ phù hợp với phạm vi câu hỏi của OP. Có nhiều triển khai hoàn chỉnh hơn xung quanh, bao gồm cả triển khai mà tôi tìm thấy trong mã nguồn JDK.
pkeller

1
[+-]?((?=\.?\d)\d*\.?\d*)thể sử dụng regex để tránh sự thay thế không? Nó sử dụng một lookahead ...
4esn0k

1
@ 4esn0k Regex đẹp quá! Tôi đã thử với nó, và nó hoạt động. Tôi có hai lưu ý: (1) không phải tất cả các công cụ regex đều hỗ trợ xác nhận chiều rộng bằng không (mặc dù hầu hết các công cụ hiện đại đều có, AFAIK) và (2) cái nhìn về phía trước chỉ là một sự thay thế bằng một tên khác: công cụ vẫn phải thử một cái gì đó và quay lại nếu nó không hoạt động. Tuy nhiên, có một sự ủng hộ cho một ý tưởng rất gọn gàng.
pkeller

7

những gì bạn cần là:

[\-\+]?[0-9]*(\.[0-9]+)?

Tôi đã thoát khỏi dấu "+" và "-" và cũng đã nhóm số thập phân với các chữ số sau của nó vì một cái gì đó như "1." không phải là một số hợp lệ.

Những thay đổi sẽ cho phép bạn so khớp số nguyên và số nổi. ví dụ:

0
+1
-2.0
2.23442

Vấn đề với biểu thức này là điều đó .1sẽ không được phép, mặc dù đầu vào như vậy được mọi người công nhận là đúng.
JDB vẫn nhớ Monica

Điều này bây giờ sẽ chấp nhận các chuỗi có độ dài bằng không -+không phải là số. Regex thật gian xảo! :)
JDB vẫn nhớ Monica

Ngoài ra, điều này không trả lời câu hỏi thực sự của OP, đó là điều \.đó không hoạt động.
JDB vẫn nhớ Monica,

7

Tôi muốn so khớp những gì mà hầu hết các ngôn ngữ coi là số hợp lệ (số nguyên và số thực):

  • '5' / '-5'

  • '1.0' / '1.' / '.1' / '-1.' / '-.1'

  • '0.45326e+04', '666999e-05', '0.2e-3', '-33.e-1'

Ghi chú:

  • preceding sign of number ('-' or '+') is optional

  • '-1.' and '-.1' are valid but '.' and '-.' are invalid

  • '.1e3' is valid, but '.e3' and 'e3' are invalid

Để hỗ trợ cả '1.' và '.1' chúng ta cần toán tử OR ('|') để đảm bảo rằng chúng ta loại trừ '.' từ khớp.

[+-]?+/- sing là tùy chọn vì ?có nghĩa là 0 hoặc 1 trận đấu

( vì chúng ta có 2 biểu thức phụ nên chúng ta cần đặt chúng trong dấu ngoặc đơn

\d+([.]\d*)?(e[+-]?\d+)? Điều này dành cho các số bắt đầu bằng một chữ số

| tách các biểu thức phụ

[.]\d+(e[+-]?\d+)? đây là cho các số bắt đầu bằng '.'

) cuối biểu thức

  • Đối với các số bắt đầu bằng '.'

[.] ký tự đầu tiên là dấu chấm (bên trong dấu ngoặc đơn hoặc nếu không nó là ký tự đại diện)

\d+ một hoặc nhiều chữ số

(e[+-]?\d+)? đây là ký hiệu khoa học không bắt buộc (0 hoặc 1 đối sánh do kết thúc bằng '?')

  • Đối với các số bắt đầu bằng một chữ số

\d+ một hoặc nhiều chữ số

([.]\d*)? tùy chọn, chúng tôi có thể có một ký tự dấu chấm một số không hoặc nhiều chữ số sau nó

(e[+-]?\d+)? đây là một ký hiệu khoa học tùy chọn

  • Ký hiệu khoa học

e nghĩa đen chỉ định số mũ

[+-]? dấu mũ tùy chọn

\d+ một hoặc nhiều chữ số

Tất cả những thứ đó kết hợp lại:

[+-]?(\d+([.]\d*)?(e[+-]?\d+)?|[.]\d+(e[+-]?\d+)?)

Để chấp nhận E:

[+-]?(\d+([.]\d*)?([eE][+-]?\d+)?|[.]\d+([eE][+-]?\d+)?)

( Các trường hợp thử nghiệm )


4

Điều này rất đơn giản: bạn đã sử dụng Java và bạn nên sử dụng \\.thay vì \.(tìm kiếm ký tự thoát trong Java).


Có thể bạn đúng ... thông báo lỗi trông giống như lỗi cú pháp ngôn ngữ lập trình hơn là lỗi phân tích cú pháp regex.
JDB vẫn nhớ Monica

3

Điều này đã làm việc cho tôi:

(?P<value>[-+]*\d+\.\d+|[-+]*\d+)

Bạn cũng có thể sử dụng cái này (không có tham số được đặt tên):

([-+]*\d+\.\d+|[-+]*\d+)

Sử dụng một số trình kiểm tra regex trực tuyến để kiểm tra nó (ví dụ: regex101)


2
^[+]?([0-9]{1,2})*[.,]([0-9]{1,1})?$

Điều này sẽ phù hợp với:

  1. 1,2
  2. 12.3
  3. 1,2
  4. 12,3

Mặc dù đoạn mã này được hoan nghênh và có thể cung cấp một số trợ giúp, nó sẽ được cải thiện đáng kể nếu nó bao gồm giải thích về cách thứclý do tại sao đoạn mã này giải quyết được vấn đề. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai, không chỉ người hỏi bây giờ! Vui lòng chỉnh sửa câu trả lời của bạn để thêm giải thích và đưa ra dấu hiệu về những hạn chế và giả định nào được áp dụng.
Toby Speight

ồ cảm ơn, tôi đang yêu thích điều này
Serg Burlaka

0
[+-]?(([1-9][0-9]*)|(0))([.,][0-9]+)?

[+-]? - dấu hiệu hàng đầu tùy chọn

(([1-9][0-9]*)|(0)) - số nguyên không có số 0 đứng đầu, bao gồm số 0 duy nhất

([.,][0-9]+)? - phần phân số tùy chọn


1
Cung cấp thêm thông tin - đối với những người không biết regexps, đó là chữ hyerogliph. Đối với những người biết họ, họ không cần nó.
peterh - Phục hồi Monica

0

Trong C ++ sử dụng thư viện regex

Câu trả lời sẽ diễn ra như thế này:

[0-9]?([0-9]*[.])?[0-9]+

Lưu ý rằng tôi không lấy biểu tượng dấu hiệu, nếu bạn muốn nó với biểu tượng dấu hiệu, nó sẽ đi về điều này:

[+-]?([0-9]*[.])?[0-9]+

Điều này cũng phân tách một số thông thường hoặc một số thập phân.


0

Trong ký hiệu c, số thực có thể xảy ra trong các hình dạng sau:

  1. 123
  2. 123.
  3. 123,24
  4. .24
  5. 2e-2 = 2 * 10 pow -2 = 2 * 0,1
  6. 4E + 4 = 4 * 10 pow 4 = 4 * 10 000

Để tạo float thường expresion, trước tiên tôi sẽ tạo "int regular expresion":

(([1-9][0-9]*)|0) will be int

Bây giờ, tôi sẽ viết các phần nhỏ của phép thám hiểm float thông thường - giải pháp là nối các phần đó với hoặc simbol "|".

Miếng, mảnh nhỏ:

- (([+-]?{int}) satysfies case 1
- (([+-]?{int})"."[0-9]*)  satysfies cases 2 and 3
- ("."[0-9]*) satysfies case 4
- ([+-]?{int}[eE][+-]?{int}) satysfies cases 5 and 6

Giải pháp cuối cùng (tập hợp các khối nhỏ):

(([+-]?{int})|(([+-]?{int})"."[0-9]*)|("."[0-9]*)|([+-]?{int}[eE][+-]?{int})


-1

cho javascript

const test = new RegExp('^[+]?([0-9]{0,})*[.]?([0-9]{0,2})?$','g');

Cái nào sẽ phù hợp với 1,23 1234,22 0 0,12 12

Bạn có thể thay đổi các phần trong dấu {}để nhận được các kết quả khác nhau về độ dài phần thập phân và phía trước của số thập phân. Điều này được sử dụng trong đầu vào để nhập số và kiểm tra mọi đầu vào khi bạn nhập chỉ cho phép những gì vượt qua.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.