Nhờ giải thích ý nghĩa của Biểu thức chính quy

Chào mọi người. Đầu xuân xin được kính chúc anh chị em năm mới an khang thịnh vượng, vạn sự như ý.
Vừa bắt đầu trở lại làm việc và học tập, mình nhờ mọi người giải thích giúp mình biểu tức chính quy trong đoạn code dưới đây :

var str = 'For more information, see Chapter 3.4.5.1';
var re = /(chapter \d+(\.\d)*)/i;
var found = str.match(re);
console.log(found);
// logs ['Chapter 3.4.5.1', 'Chapter 3.4.5.1', '.1']

Xin cho hỏi, biểu thức đã được khớp thế nào mà kết quả trả về có 2 giá trị đầu tiên giống nhau và giá trị thứ 3 là .1 cũng được thỏa mãn là sao ạ (vì mình thấy trong biểu thức chính quy có dính tới cả thằng chapter nữa mà ).

Theo như regex của bạn:

  • (chapter \d+(\.\d)*) là group 0 (full match)
  • chapter \d+(\.\d)* là group 1. Group 1 không khác gì group 0 tại vì chỉ cần thêm 1 cặp ngoặc bao ngoài group 0 là có group 1. Bỏ đi cho đỡ thừa.
  • \.\d là group 2.

Do vậy sẽ có 1 cái gì đó sẽ match vào group 2, đó chính là .1 (vì * có nghĩa là match nhiều nhất có thể -> pattern .1 cuối cùng sẽ match vào group 2). Bạn thử bỏ cái * xem, bạn sẽ thấy .4 sẽ match vào group 2.

3 Likes

Em thấy hơi khó hiểu ,anh có cách nào diễn giải dễ hỉu hơn chút xíu cho e hình dung được không anh
Cám ơn anh !

Bạn thử nhìn vào các matching group ở link dưới:

rồi xem bạn còn chưa hiểu thế nào.

2 Likes

Bạn có thể viết lại cái regex thế này cho gọn.

/chapter [\.?\d]+/gi

Còn về cách hoạt động cụ thể thì có thể dùng http://regex101.com và đọc tài liệu về nó

Còn về matching group thì hiểu đơn giản là bao nhiêu cặp ngoặc đơn () thì bấy nhiêu matching group

3 Likes

Chỗ này em còn thắc mắc ạ:

Khi khớp đến Group này (\.\d)* dấu * tức là nhiều nhất có thể , vậy tại sao kết quả trả về lại chỉ là .1 mà không phải là .4.5.1 ạ.

Anh giải thích thêm cho e đoạn này với .

Đầu tiên nó sẽ match cái trong ngoặc trước sau đó match cái trong ngoặc kèm *. Trong trường hợp này, bạn nên dùng + thay vì * nếu dùng regex này trên một văn bản lớn. Vì từ chapter rất thông dung, dễ tạo ra kết quả ko mong muốn

2 Likes

Không phải. Ý em là chưa hiểu ở chỗ (\.\d)* :
\. : là biểu diễn cho dấu .
\d : là biểu diễn cho số 0 - 9
* : là khớp nhiều nhất có thể

=> Vậy sao kết quả trả về không phải là .4.5.1 (nhiều nhất có thể) , mà lại chỉ là .1 thôi

à, em hiểu rồi, dấu * bên ngoài cặp ngoặc () nên không tính trong Group

====================================

Nhưng mà thế cũng không phải, nếu khớp trong group (\.\d) thì kết quả trả về phải là .4 chứ ạ

String.prototype.match sẽ khớp với giá trị cuối cùng, không phải giá trị đầu tiên

2 Likes

Nhưng mà , em thử ví dụ thế này:

var str = 'For more information, see Chapter 3.4.5.1';
var re = /\.\d/i;
var found = str.match(re);
document.write(found);

Kết quả trả về vẫn là .4 đó thôi.

Trong cái anh đưa ra String.prototype.match thì cái prototype là gì đó ạ ???

trên trang regex101 nó có giải thích cặn kẽ luôn mà:

A repeated capturing group will only capture the last iteration. Put a capturing group around the repeated group to capture all iterations or use a non-capturing group instead if you’re not interested in the data

(\.\d) thì bạn chỉ capture 1 dấu . và 1 chữ số => là .4, .5, hoặc .1, và nó cũng nói rõ là với repeated capturing group nghĩa là (…)+ hay (…)* có nhiều cái match, nó sẽ lấy cái cuối cùng là .1. Cái ví dụ của bạn ko phải là repeated capturing group nên nó trả về cái đầu tiên nó tìm thấy là .4. Nếu sửa lại là (\.\d)+ thì nó sẽ trả về group 1 là .1 là cái cuối cùng.

thêm dấu () bao quanh dấu * và cái group kia nữa là được:
(chapter \d+((\.\d)*))

Full match	26-41	`Chapter 3.4.5.1`
Group 1.	n/a	`Chapter 3.4.5.1`
Group 2.	n/a	`.4.5.1`
Group 3.	n/a	`.1`

lỡ có “chapter 1.12” thì (\.\d) chỉ lấy có 1.1 chữ ko lấy 1.12 @_@ thêm dấu + vào nữa cho đủ: (\.\d+)

nếu bạn ko cần cái group 3 kia thì thêm ?: vào trong (\.\d), nó sẽ ko capture group 3 nữa: (?:\.\d)

4 Likes

Mọi người ơi, Giờ mình muốn kiểm tra 1 chuỗi chỉ được phép chứa các chữ cái và chữ số và Chuỗi đó phải chứa ít nhất 1 ký tự thường, 1 ký tự hoa và 1 chữ số.
Mình có viết biểu thức chính quy thế này:

^([a-z]+[A-Z]+\d+|[A-Z]+[a-z]+\d+|\d+[A-Z]+[a-z]+)$

Tuy nhiên mình thấy nó hơi dài vì lại phải đổi chỗ 3 cái cho nhau.

Không biết có cách nào hay và ngắn gọn hơn không ạ

Bạn viết hàm kiểm tra dựa vào việc đếm số lượng của từng loại. Trường hợp này không cần dùng regex cũng được.

3 Likes

nghe giống password:

gần như copy thẳng từ answer luôn @_@
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]+$

2 Likes

Biểu thức này không vượt qua case chapter 1.22222222.222222 rồi. /(chapter \d+(\.\d)*)/i là 1 số theo sau 1 kí tự chấm “.”.

1 Like

Cám ơn bạn nhiều ạ ::::::::::::::::slight_smile:

Bạn chắc chứ ?

[DEAD LINK]

Đừng giới hạn password như vậy. Please

https://blog.codinghorror.com/password-rules-are-bullshit/

3 Likes

Cho mình hỏi :

Ký hiệu ?= nó dùng để khớp nếu theo sau nó là một ký tự được ấn định trước, ví dụ x(?=y) thì x sẽ được khớp nếu nó được theo sau bởi y, nhưng trong trường hợp này ở trước ?= trước dấu ( không có ký tự gì cả (tức là trường hợp này bị khuyết x) , thì mình hiểu nó thế nào ạ ???

Cám ơn mọi người !

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?