Sự khác biệt giữa \ A \ z và ^ $ trong các biểu thức chính quy của Ruby


196

Trong tài liệu tôi đọc:

Sử dụng \ A và \ z để khớp với điểm bắt đầu và kết thúc của chuỗi, ^ và $ khớp với điểm bắt đầu / kết thúc của một dòng.

Tôi sẽ áp dụng một biểu thức thông thường để kiểm tra tên người dùng (hoặc e-mail là giống nhau) được gửi bởi người dùng. Tôi nên sử dụng biểu thức nào validates_format_oftrong mô hình? Tôi không thể hiểu được sự khác biệt: Tôi đã luôn sử dụng ^ và $ ...


Câu trả lời:


226

Nếu bạn phụ thuộc vào biểu thức chính quy để xác thực, bạn luôn muốn sử dụng \A\z. ^$sẽ chỉ khớp với nhau cho đến khi một ký tự dòng mới, có nghĩa là họ có thể sử dụng email như thế nào me@example.com\n<script>dangerous_stuff();</script>và vẫn có hiệu lực, vì regex chỉ nhìn thấy mọi thứ trước đó \n.

Đề xuất của tôi sẽ hoàn toàn tước bỏ các dòng mới từ tên người dùng hoặc email trước đó, vì gần như không có lý do chính đáng nào cho một. Sau đó, bạn có thể sử dụng EITHER một cách an toàn \A \zhoặc ^ $.


13
@Ragmaanir là đúng, nó nên bằng chữ nhỏ \zthay vì \Z!
Petr

10
+1 Cảm ơn! Mặc dù tôi sẽ không đồng ý với đề xuất của bạn: A) Đừng thêm công việc / xử lý không cần thiết nếu có một sự bắt kịp phù hợp và B) đặc biệt là nếu điều đó cho phép bạn vẫn lười biếng trong việc phân biệt giữa hai điều này. Bạn có thể không phải lúc nào cũng ở trong một vị trí để thao tác chuỗi, chỉ với Regex, vì vậy hãy cam kết đúng với bộ nhớ và biết sự khác biệt!
dooleyo

1
Tôi không hiểu ví dụ với nội dung nguy hiểm vì trong cả hai trường hợp, người ta có thể bao gồm nội dung nguy hiểm trong chuỗi, có hoặc không có dòng mới, đó sẽ là một khai thác cần được sửa chữa bằng cách khử trùng và xác thực html.
Jayr Motta

2
@JayrMotta những gì trình diễn cho thấy là những thứ nguy hiểm sẽ hoàn toàn bỏ qua toàn bộ kiểm tra regex của bạn . Vì vậy, ngay cả khi bạn đang kiểm tra những thứ nguy hiểm trong regex của mình, nó sẽ bị bỏ qua nếu bạn sử dụng $để kiểm tra "kết thúc chuỗi" thay vì \z.
Bác sĩ Blue

177

Theo Pickaxe :

^ Phù hợp với sự bắt đầu của một dòng.

$ Phù hợp với kết thúc của một dòng.

\A Khớp với phần đầu của chuỗi.

\z Khớp với phần cuối của chuỗi.

\Z Khớp với phần cuối của chuỗi trừ khi chuỗi kết thúc bằng a "\n", trong trường hợp đó, nó khớp ngay trước dấu "\n".

Vì vậy, sử dụng \Avà viết thường \z. Nếu bạn sử dụng \Zai đó có thể lẻn vào một nhân vật dòng mới. Điều này không nguy hiểm tôi nghĩ, nhưng có thể làm hỏng các thuật toán giả định rằng không có khoảng trắng trong chuỗi. Tùy thuộc vào ràng buộc regex và độ dài chuỗi của bạn, ai đó có thể sử dụng tên vô hình chỉ bằng một ký tự dòng mới.

Việc triển khai Regex của JavaScript được coi \Alà một nghĩa đen 'A'( ref ). Vì vậy, xem bản thân ra khỏi đó và kiểm tra.


16

Bắt đầu và kết thúc của một chuỗi có thể không nhất thiết giống như bắt đầu và kết thúc của một dòng. Hãy tưởng tượng nếu bạn sử dụng như sau đây là chuỗi thử nghiệm của bạn:

tôi
tên

Andrew

Lưu ý rằng chuỗi có nhiều dòng trong đó - ^và các $ký tự cho phép bạn khớp đầu và cuối của các dòng đó (về cơ bản coi \nký tự là một dấu phân cách) trong khi \A\Zcho phép bạn khớp đầu và cuối của toàn bộ chuỗi.


1
Câu trả lời tốt nhất theo ý kiến ​​của tôi. "về cơ bản coi nhân vật \ n như một thước đo" thực sự giúp tôi hiểu, cảm ơn bạn.
Flyout91

11

Sự khác biệt theo ví dụ

  1. /^foo$/phù hợp với bất kỳ điều nào sau đây, /\Afoo\z/không:
whatever1
foo
whatever2
foo
whatever2
whatever1
foo
  1. /^foo$//\Afoo\z/tất cả phù hợp với những điều sau đây:
foo
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.