Thử nghiệm VBScript RegExp

Liên hệ QC

Quang_Hải

Thành viên gạo cội
Tham gia
21/2/09
Bài viết
6,051
Được thích
7,950
Nghề nghiệp
Làm đủ thứ
Chúng ta cùng khảo sát những ứng dụng cơ bản của VBScript RegExp
Thông thường khi muốn tách số ra khỏi 1 chuỗi lẫn lộn vừa số vừa chữ thì chúng ta hay dùng vòng lặp để xử lý, nhưng với VBR thì công việc này khá đơn giản với dạng code thế này

Ví dụ này ta chỉ chú ý đến .Pattern="\D"
Phương thức này sẽ tìm tất cả các ký tự không phải là số

Tiếp theo ta dùng phương thức .Replace để thay các ký tự được tìm thấy bằng chuỗi rỗng (xoá các ký tự đó) để còn lại kết quả là những con số

PHP:
Sub RegExp1()
Dim VBR As Object, kq
Set VBR = CreateObject("VBScript.RegExp")
With VBR
   For i = 1 To 5
      .Global = True
      .Pattern = "\D"
      Cells(i, 2) = .Replace(Cells(i, 1), "")
   Next
End With
End Sub

Cũng với code tương tự chúng ta có thể cộng các con số đựơc tìm thấy lại với nhau
Ở đây ta để ý đến phần .Pattern="\B"
Nếu chúng ta sử dụng .Pattern="" thì có nghĩa ta đang nói đến bắt đầu và kết thúc của 1 ký tự, khi ta muốn thêm dấu + giữa các con số tìm được thì ta có kết quả thế này: +1+2+3+4+5+

Nhưng với .Pattern = "\B" thì sẽ loại được dấu cộng không mong muốn ở đầu và cuối của dãy số tìm được. Sau đó chúng ta dùng hàm Evaluate để biến chuỗi này thành bài toán cộng

PHP:
Sub RegExp2()
Dim VBR As Object, kq
Set VBR = CreateObject("VBScript.RegExp")
With VBR
   For i = 1 To 5
      .Global = True
      .Pattern = "\D"
      kq = .Replace(Cells(i, 1), "")
      .Pattern = "\B"
      Cells(i, 2) = Evaluate(.Replace(kq, "+"))
   Next
End With
End Sub

Để tách lấy các ký tự trong 1 chuỗi lẫn lộn số và chữ ta sử dụng .Pattern="\d"
"\d" sẽ tìm tất cả con số trong chuỗi để xử lý
PHP:
Sub RegExp3()
Dim VBR As Object, kq
Set VBR = CreateObject("VBScript.RegExp")
With VBR
   For i = 1 To 5
      .Global = True
      .Pattern = "\d"
      Cells(i, 2) = .Replace(Cells(i, 1), "")
   Next
End With
End Sub
Nhưng không may trong chuỗi ký tự có những ký tự không phải là những mẫu tự, ta có thể dùng thế này "\W" kết hợp với "\d" để khử hết các ký tự đó. Nhưng không hiểu sao ký tự _ vẫn không được xử lý triệt để nên tôi phải kết hợp thêm dấu _ trong Pattern
Lưu ý là chúng ta không bàn đến tiếng việt có dấu nha

PHP:
Sub RegExp4()
Dim VBR As Object, kq
Set VBR = CreateObject("VBScript.RegExp")
With VBR
   For i = 1 To 5
      .Global = True
      .Pattern = "[\W\d,_]"
      Cells(i, 2) = .Replace(Cells(i, 1), "")
   Next
End With
End Sub
 
Lần chỉnh sửa cuối:
Nghiên cứu phân tích hết cách vẫn không hiểu nổi thuật toán của code này.

Anh siwtom vui lòng dành ít thời gian giải thích giúp em nguyên tắc của thuật toán trong code này để em có thể ứng dụng trong những trường hợp khác

Cái này thì đơn giản thôi.
Ta tìm các đoạn: là chuỗi các ký tự không phải là "dấu cách", tab ..., tiếp theo là chuỗi ký tự, và đoạn cuối là chuỗi gồm có 1 ký tự \s và sau nó là chuỗi ký tự không là \s.
1. Chú ý là đoạn - chuỗi tìm được luôn là cả chuỗi nguồn - họ + tên lót + tên.
2. 3 đoạn nhỏ của pattern tôi cho vào trong cặp ngoặc đơn "()"

Khi đã có đoạn cho vào ngoặc (có ngoại lệ) thì các đoạn đó được nhớ để:

a. Trong phần tiếp theo của pattern có thể dùng \1, \2, \3, ... để ám chỉ là chỗ đó phải có "giá trị" trong kết quả trả về "y hệt" như chỗ mà nó truy cập ngược lại. Chú ý "y hệt" ở đây là "y hệt" về "giá trị" chứ không chỉ y hệt về dạng.

vd. ta có pattern = "(\d+)[a-z]+\1"

Nếu kết quả trả về là 12345klm*** thì có nghĩa là *** = 12345
Chỗ \1 phải có giá trị y hệt như "cụm nhớ" thứ nhất, tức cụm nhớ 1.
Nếu có nhiều cụm nhớ thì chúng được đánh số là 1, 2, 3, ...

b. Trong phương thức Replace có thể dùng các cụm được ghi nhớ, nhưng viết là $1, $2, $3, ...
(\1, \2, \3 dùng trong pattern)

c. Các cụm được ghi nhớ thì chúng được nhớ trong tập SubMatches, và nếu ta muốn dùng chúng thì đọc ra.

Giả sử với pattern ở trên và code là:

[GPECODE=vb]
...
Set colMatches = .Execute(text)
for k = 0 to colMatches.count - 1
Set match = colMatches.Item(k)
s1 = match.Value
Debug.Print s1
for n = 0 to match.SubMatches.count - 1
s2 = match.SubMatches(n)
Debug.Print s2
next n
next k
[/GPECODE]

Và chỉ có 2 kết quả trả về là "12345klm12345" và "54a54" thì có nghĩa là

A1. k = 0, 1 (2 kết quả tìm được) và n = 0 (nhớ 1 cụm)

A2.
Với k = 0 có kết quả in là

12345klm12345 - s1 <-- đây là đoạn tìm được
12345 - s2 <-- là đoạn được nhớ ứng với đoạn pattern đặt trong ngoặc

Với k = 1

54a54 - s1 <-- đây là đoạn tìm được
54 - s2 <-- là đoạn được nhớ ứng với đoạn pattern đặt trong ngoặc
-------------
Trở lại bài của ta thì
- đoạn đầu đặt trong ngoặc chính là Họ --> \1, $1, SubMatches(0)
- đoạn thứ hai đặt trong ngoặc chính là Tên Lót --> \2, $2, SubMatches(1)
- đoạn thứ ba đặt trong ngoặc chính là Tên --> \3, $3, SubMatches(2)

Giả sử dữ liệu vào (sau khi Trim) là "Lê Diễm My" và cần trả về Tên, tức index = 3:

Đoạn tìm thấy là "Lê Diễm My". $1, $2, $3 "ám chỉ" các chuỗi "Lê", " Diễm", " My"
Và
tachhoten = Trim(.Replace(Trim(cell), "$" & index)) =
tachhoten = Trim(.Replace("Lê Diễm My", "$3")) =
tachhoten = Trim(.Replace("Lê Diễm My", " My")) = Trim(" My") = "My"
-----------------
Giải thích thêm:
Code s = objRe.Replace(hichic, "$3") có nghĩa là: Trong chuỗi nguồn hichic ở những vị trí có chuỗi tìm được dựa theo pattern thì thay những chuỗi tìm được đó bằng "cụm nhớ thứ 3". Sau khi thay thế thì chuỗi cuối cùng được trả về.
Ta có chuỗi nguồn là "Lê Diễm My", chuỗi tìm được trong chuỗi nguồn thỏa pattern cũng chính là "Lê Diễm My". "cụm nhớ thứ 3" chính là " My".
Vậy "Trong chuỗi nguồn ở những vị trí có chuỗi tìm được dựa theo pattern thì thay những chuỗi tìm được đó bằng "cụm nhớ thứ 3" = Trong chuỗi "Lê Diễm My" thay "Lê Diễm My" bằng " My".
Vậy kết quả trả về là " My", mà Trim(" My") = "My"
-------------
Vấn đề này và nhiều cấu trúc khác tôi đã có lần viết trong chủ đề này nhưng sau một thời gian không thấy ai có ý kiến, hỏi, thậm chí không có một "dấu vết" nào là đã có người đọc nên tôi xóa đi.
 
Lần chỉnh sửa cuối:
Upvote 0
Cái này thì đơn giản thôi.
Ta tìm các đoạn: là chuỗi các ký tự không phải là "dấu cách", tab ..., tiếp theo là chuỗi ký tự, và đoạn cuối là chuỗi gồm có 1 ký tự \s và sau nó là chuỗi ký tự không là \s.
1. Chú ý là đoạn - chuỗi tìm được luôn là cả chuỗi nguồn - họ + tên lót + tên.
2. 3 đoạn nhỏ của pattern tôi cho vào trong cặp ngoặc đơn "()"

Khi đã có đoạn cho vào ngoặc (có ngoại lệ) thì các đoạn đó được nhớ để:

a. Trong phần tiếp theo của pattern có thể dùng \1, \2, \3, ... để ám chỉ là chỗ đó phải có "giá trị" trong kết quả trả về "y hệt" như chỗ mà nó truy cập ngược lại. Chú ý "y hệt" ở đây là "y hệt" về "giá trị" chứ không chỉ y hệt về dạng.

vd. ta có pattern = "(\d+)[a-z]+\1"

Nếu kết quả trả về là 12345klm*** thì có nghĩa là *** = 12345
Chỗ \1 phải có giá trị y hệt như "cụm nhớ" thứ nhất, tức cụm nhớ 1.
Nếu có nhiều cụm nhớ thì chúng được đánh số là 1, 2, 3, ...

b. Trong phương thức Replace có thể dùng các cụm được ghi nhớ, nhưng viết là $1, $2, $3, ...
(\1, \2, \3 dùng trong pattern)

c. Các cụm được ghi nhớ thì chúng được nhớ trong tập SubMatches, và nếu ta muốn dùng chúng thì đọc ra.

Giả sử với pattern ở trên và code là:

[GPECODE=vb]
...
Set colMatches = .Execute(text)
for k = 0 to colMatches.count - 1
Set match = colMatches.Item(k)
s1 = match.Value
Debug.Print s1
for n = 0 to match.SubMatches.count - 1
s2 = match.SubMatches(n)
Debug.Print s2
next n
next k
[/GPECODE]

Và chỉ có 2 kết quả trả về là "12345klm12345" và "54a54" thì có nghĩa là

A1. k = 0, 1 (2 kết quả tìm được) và n = 0 (nhớ 1 cụm)

A2.
Với k = 0 có kết quả in là

12345klm12345 - s1 <-- đây là đoạn tìm được
12345 - s2 <-- là đoạn được nhớ ứng với đoạn pattern đặt trong ngoặc

Với k = 1

54a54 - s1 <-- đây là đoạn tìm được
54 - s2 <-- là đoạn được nhớ ứng với đoạn pattern đặt trong ngoặc
-------------
Trở lại bài của ta thì
- đoạn đầu đặt trong ngoặc chính là Họ --> \1, $1, SubMatches(0)
- đoạn thứ hai đặt trong ngoặc chính là Tên Lót --> \2, $2, SubMatches(1)
- đoạn thứ ba đặt trong ngoặc chính là Tên --> \3, $3, SubMatches(2)

Giả sử dữ liệu vào (sau khi Trim) là "Lê Diễm My" và cần trả về Tên, tức index = 3:

Đoạn tìm thấy là "Lê Diễm My". $1, $2, $3 "ám chỉ" các chuỗi "Lê", " Diễm", " My"
Và
tachhoten = Trim(.Replace(Trim(cell), "$" & index)) =
tachhoten = Trim(.Replace("Lê Diễm My", "$3")) =
tachhoten = Trim(.Replace("Lê Diễm My", " My")) = Trim(" My") = "My"
-----------------
Giải thích thêm:
Code s = objRe.Replace(hichic, "$3") có nghĩa là: Trong chuỗi nguồn hichic ở những vị trí có chuỗi tìm được dựa theo pattern thì thay những chuỗi tìm được đó bằng "cụm nhớ thứ 3". Sau khi thay thế thì chuỗi cuối cùng được trả về.
Ta có chuỗi nguồn là "Lê Diễm My", chuỗi tìm được trong chuỗi nguồn thỏa pattern cũng chính là "Lê Diễm My". "cụm nhớ thứ 3" chính là " My".
Vậy "Trong chuỗi nguồn ở những vị trí có chuỗi tìm được dựa theo pattern thì thay những chuỗi tìm được đó bằng "cụm nhớ thứ 3" = Trong chuỗi "Lê Diễm My" thay "Lê Diễm My" bằng " My".
Vậy kết quả trả về là " My", mà Trim(" My") = "My"
-------------
Vấn đề này và nhiều cấu trúc khác tôi đã có lần viết trong chủ đề này nhưng sau một thời gian không thấy ai có ý kiến, hỏi, thậm chí không có một "dấu vết" nào là đã có người đọc nên tôi xóa đi.

Cảm ơn anh. Em đã copy các bài giảng của anh về 1 file word để đọc lúc rảnh. Nhưng sao mà nó rối quá. Chắc phải mất nhiều thời gian mới thấm nổi. Khó quá.
 
Lần chỉnh sửa cuối:
Upvote 0
Cảm ơn anh. Em đã copy các bài giảng của anh về 1 file word để đọc lúc rảnh. Nhưng sao mà nó rối quá. Chắc phải mất nhiều thời gian mới thấm nổi. Khó quá.

Trong lập trình nếu bạn chỉ đọc bài của người khác viết, đọc help thì bạn thấy nhiều chỗ không hiểu. Nếu đọc xong bỏ đấy thì bạn chả học được gì.
Với mỗi vấn đề thì dù tự đoc help hay đọc hướng dẫn của người khác thì bước tiếp theo phải là tự viết code. Trong trường hợp cụ thể này là phải tự nghĩ ra vài ví dụ --> viết code --> trong code vài chỗ in ra các kết quả trung gian và kết quả cuối --> kiểm tra kết quả tìm được có đúng dạng pattern hay không, những chỗ mà "người ta" nói là sẽ được nhớ có đúng là được nhớ hay không, chúng có được dùng trong Replace hay không v...v.
Viết vài code cho mỗi trường hợp, mỗi cấu trúc pattern thì tự bạn sẽ thấy rõ ra thôi. Như thế mới là học.
-----------
Ví dụ với pattern = "(\S+)(.*)(\s\S+)"
Nếu chuỗi nguồn là Họ + tên lót + Tên, vd. "Lê Diễm My" thì nhìn vào pattern bạn sẽ thấy là toàn bộ Trim(chuỗi nguồn) "khớp" với pattern. Đúng không? Vậy nếu bạn tìm đoạn khớp thì cũng chính chuỗi nguồn (sau khi Trim) sẽ được trả về.Chả ai cần kết quả ấy làm gì.
Nhưng pattern được chia làm 3 đoạn và "người ta" nói là do vậy chúng được "ghi nhớ" để

1. Để có thể trong phần tiếp theo truy cập ngược lại tới chúng bằng cách dùng \1, \2, \3, ...
2. Để nếu có nhu cầu thì đọc chúng ra từ SubMatches
3. Để nếu muốn thì sử dụng chúng trong Replace - dưới dạng $1, $2, $3, ...

Từ những điều "người ta" nói thì

1. objRE.Execute(text).Item(0).Value sẽ trả về "Lê Diễm My" vì toàn bộ chuỗi nguồn khớp với pattern
Tôi luôn có thói quen viết tường minh, nhiều người viết tắt là objRE.Execute(text)(0)

2. Theo lời "người ta" thì 3 đoạn trong kết quả trả về tương ứng với 3 đoạn trong ngoặc của pattern sẽ được nhớ trong SubMatches(0), SubMatches(1) và SubMatches(2). Hơn thế nữa có thể dùng chúng trực tiếp trong Replace ở dạng $1, $2, $3 - mỗi $1, $2, $3 trước tiên được thay bằng các đoạn được ghi nhớ tương ứng.

Trong vd. cụ thể này thì $1 = "Lê", $2 = " Diễm", $3 = " My"

Thế thay vì viết tachhoten = Trim(.Replace(Trim(cell), "$" & index)) tôi viết
tachhoten = Trim(.Replace(Trim(cell), "$3 $1 $2"))
thì trong tachhoten có gì?

"$3 $1 $2" = " My Lê Diễm" - cứ thế vào chỗ $1, $2, $3 những giá trị được ghi nhớ thôi

Vậy code có nghĩa là: Trong chuỗi nguồn là "Lê Diễm My" ở chỗ chuỗi khớp cũng chính là "Lê Diễm My" thay chuỗi khớp này bằng "$3 $1 $2" = " My Lê Diễm". Tức thay "Lê Diễm My" bằng " My Lê Diễm". Mà Trim(" My Lê Diễm") = "My Lê Diễm"
Kết quả chính là đảo tên chứ còn gì nữa: "Họ Tên Lót Tên" --> "Tên Họ Tên Lót"

code ví dụ:

[GPECODE=vb]
Sub daoten()
Dim objRe As Object, s As String
s = "Le Diem My"
Set objRe = CreateObject("VBScript.RegExp")
objRe.pattern = "(\S+)(.*)(\s\S+)"
s = Trim(objRe.replace(s, "$3 $1$2"))
Debug.Print s ' <-- My Le Diem
End Sub
[/GPECODE]

Nhưng thực chất thì code daoten phải lường được trường hợp giữa Họ Tên có nhiều dấu cách để loại bớt, và do thứ tự "Họ Tên Lót" không thay đổi nên có thể gộp chúng làm 1

[GPECODE=vb]
Function daoten(ByVal hoten As String) As String
Dim objRe As Object
Set objRe = CreateObject("VBScript.RegExp")
objRe.pattern = "(.+\s)(\S+)"
daoten = WorksheetFunction.Trim(objRe.replace(hoten, "$2 $1"))
End Function

Sub mytest()
Dim s As String
s = daoten("Le Diem My")
Debug.Print s ' <-- My Le Diem"
End Sub
[/GPECODE]
-----------------------
Ở trên ta có trường hợp chỉ có 1 đoạn khớp thỏa pattern. Thế nếu có nhiều đoạn khớp thì Replace sẽ hoạt động như thế nào?
vd. objRe.replace(s, "$1") sẽ vận hành thế nào nếu có nhiều kết quả trả về? Vì với mỗi kết quả thì $1 lại khác mà.

Nhắc lại cụ thể hơn. Giả sử trong chuỗi nguồn có n đoạn khớp với pattern. Mỗi đoạn khớp đó được thay bằng thông số thứ hai của Replace mà trong đó $1, $2, $3, ... là của đoạn khớp đang được thay.
Chạy code sau sẽ rõ ngay

[GPECODE=vb]
Sub def()
Dim objRe As Object, s As String
s = "abc 12345klm12345 d54efg54 2011thang2011xyz"
Set objRe = CreateObject("VBScript.RegExp")
objRe.Global = True
objRe.pattern = "(\d+)[a-z]+\1"
s = objRe.replace(s, "$1")
Debug.Print s
End Sub
[/GPECODE]

Ta có chuỗi nguồn là "abc 12345klm12345 d54efg54 2011thang2011xyz" mà 3 đoạn khớp với pattern có mầu đỏ, xanh da trời, xanh lá cây.
Đoạn khớp đỏ "12345klm12345" sẽ được thay bằng $1 của nó là "12345". Đoạn khớp xanh da trời "54efg54" sẽ được thay bằng $1 của nó là "54". Đoạn khớp xanh lá cây "2011thang2011" sẽ được thay bằng $1 của nó là "2011". Kết quả sau khi Replace phải là "abc 12345 d54 2011xyz"
Và ta thấy là đúng như vậy.
-------------------------
Tôi không muốn và sẽ không viết dài nữa. Nếu Hải quan tâm tới những bài tôi đã xóa thì tôi có thể gửi vào tin nhắn.
 
Lần chỉnh sửa cuối:
Upvote 0
Trong lập trình nếu bạn chỉ đọc bài của người khác viết, đọc help thì bạn thấy nhiều chỗ không hiểu. Nếu đọc xong bỏ đấy thì bạn chả học được gì.
Với mỗi vấn đề thì dù tự đoc help hay đọc hướng dẫn của người khác thì bước tiếp theo phải là tự viết code. Trong trường hợp cụ thể này là phải tự nghĩ ra vài ví dụ --> viết code --> trong code vài chỗ in ra các kết quả trung gian và kết quả cuối --> kiểm tra kết quả tìm được có đúng dạng pattern hay không, những chỗ mà "người ta" nói là sẽ được nhớ có đúng là được nhớ hay không, chúng có được dùng trong Replace hay không v...v.
Viết vài code cho mỗi trường hợp, mỗi cấu trúc pattern thì tự bạn sẽ thấy rõ ra thôi. Như thế mới là học.
-----------
Ví dụ với pattern = "(\S+)(.*)(\s\S+)"
Nếu chuỗi nguồn là Họ + tên lót + Tên, vd. "Lê Diễm My" thì nhìn vào pattern bạn sẽ thấy là toàn bộ Trim(chuỗi nguồn) "khớp" với pattern. Đúng không?
Nếu chuỗi gốc là "Lê Thị Diễm My" nhưng với Pattern = "(\S+)(.*)(\s\S+)" thì em không hiểu tại sao (.*) có thể nhặt ra được cụm Thị Diễm

Nếu Hải quan tâm tới những bài tôi đã xóa thì tôi có thể gửi vào tin nhắn.
Em nghĩ là những bài viết của anh rất hữu ích đối với em. Anh vui lòng gởi vào tin nhắn riêng giúp em.
Nói thật với anh rằng em là 1 trong những người rất chịu lao vào tự viết code để tự thân có thể ngộ ra vấn đề.
Cảm ơn anh rất nhiều về những bài giảng rất chi tiết.
 
Lần chỉnh sửa cuối:
Upvote 0
Nếu chuỗi gốc là "Lê Thị Diễm My" nhưng với Pattern = "(\S+)(.*)(\s\S+)" thì em không hiểu tại sao (.*) có thể nhặt ra được cụm Thị Diễm.

1. Thế " Thị Diễm" có khớp với ".+" không? Khớp, đúng không?
2. Mặc định thì RegExp luôn "cố" trả về đoạn khớp với pattern mà "dài nhất" có thể.

Rõ ràng toàn bộ chuỗi "Lê Thị Diễm My" khớp với pattern. Vì lúc đó có thể coi "Lê" khớp với "\S+", " Thị Diễm" khớp với ".+", và " My" khớp với "\s\S+"
Chúng có khớp thật không? Thật mà.

Tất nhiên chuỗi "Lê Thị Diễm" cũng thỏa pattern nhưng mặc định (default) thì RegExp "cố" tìm chuỗi dài nhất mà thỏa pattern
Có thể thay đổi mặc định, tức tìm chuỗi thỏa pattern "ngắn" nhất có thể. Những vấn đề này tôi đã viết 2 tháng trước mà chả ai quan tâm. Bây giờ xóa rồi thì lại phải trình bầy lại. Chán quá.
-------------
Vấn đề dài (default) và ngắn thì trong bài viết của tôi nó được gọi là Greedy (default) và Non-greedy
 
Upvote 0
Với code này chúng ta sẽ tìm được những cặp từ lặp lại 2 lần liên tục và loại bỏ 1 từ bị trùng. Xin hỏi nếu chuỗi ban đầu là "Dien Dan Giai Giai Phap Phap Phap Excel Excel" có từ Phap lặp lại 3 lần thì chúng ta sẽ viết Pattern thế nào để chỉ còn 1 từ Phap trong chuỗi kết quả?
PHP:
Sub reg1()
Dim Str As String
Str = "Dien Dan Giai Giai Phap Phap Excel Excel"
With CreateObject("vbscript.regexp")
   .Global = True
   .ignorecase = True
   .Pattern = "\b(\S+)\s\b\1"
   MsgBox .Replace(Str, "$1")
End With
End Sub
Sau khi phân tích mình đã xử lý vấn đề thế này có hợp lý hay không? Hay còn có cách viết pattern gọn hơn
PHP:
Sub reg1()
Dim Str As String
Str = "Dien Dan Giai Giai Phap Phap Phap Excel Excel"
With CreateObject("vbscript.regexp")
   .Global = True
   .ignorecase = True
   .Pattern = "\b(\S+)\s\b\1"
   MsgBox .Replace(.Replace(Str, "$1"), "$1")
End With
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Sau khi phân tích mình đã xử lý vấn đề thế này có hợp lý hay không? Hay còn có cách viết pattern gọn hơn
PHP:
Sub reg1()
Dim Str As String
Str = "Dien Dan Giai Giai Phap Phap Phap Excel Excel"
With CreateObject("vbscript.regexp")
   .Global = True
   .ignorecase = True
   .Pattern = "\b(\S+)\s\b\1"
   MsgBox .Replace(.Replace(Str, "$1"), "$1")
End With
End Sub
Thế có 5 hoặc nhiều hơn chữ "pháp " liên tục thì sao? Không lẽ cứ lồng .Replace(.Replace(.Replace(... hoài sao.

Thử cái này xem:
PHP:
Sub Test()
Dim Str As String
Str = "Dien Dan Giai Giai Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Excel Excel"
With CreateObject("vbscript.regexp")
   .Global = True
   .ignorecase = True
   .Pattern = "(\S+ )(\1)+"
   MsgBox Trim(.Replace(Str & " ", "$1"))
End With
End Sub
 
Upvote 0
Thêm một cách để xóa tất cả các từ bị "cà lăm":
Mã:
Sub Test2()
    Dim Str As String
    Str = "Dien Dan Giai Giai Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Excel Excel Excel Excel"
    With CreateObject("vbscript.regexp")
        .Global = True
        .ignorecase = True
        .Pattern = "(\w+)(?:\s+\1)+"
        MsgBox .Replace(Str, "$1")
    End With
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Thêm một cách để xóa tất cả các từ bị "cà lăm":
Mã:
Sub Test2()
    Dim Str As String
    Str = "Dien Dan Giai Giai Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Phap Excel Excel Excel Excel"
    With CreateObject("vbscript.regexp")
        .Global = True
        .ignorecase = True
        .Pattern = "(\w+)(?:\s+\1)+"
        MsgBox .Replace(Str, "$1")
    End With
End Sub
Anh test code với chuỗi này xem: An cung GPE
 
Upvote 0
Anh test code với chuỗi này xem: An cung GPE

Nếu tôi hiểu được ý của Hải thì code của bạn cũng sai.
Tôi hiểu là Hải muốn nói tới các TỪ lặp lại. Các TỪ chứ không phải là "một phần của từ".
Vì chả lý gì ta lại "lược" chuỗi "Danh anh di" thành "Danh di".
"Lược" là để loại bỏ các TỪ thừa cho câu nó gọn chứ không phải lược để thay nghĩa của câu.
Tất nhiên tôi không khẳng định là chỉ có tôi hiểu được ý của Hải. Ý kiến thôi chứ không áp đặt.
 
Upvote 0
Nếu tôi hiểu được ý của Hải thì code của bạn cũng sai.
Tôi hiểu là Hải muốn nói tới các TỪ lặp lại. Các TỪ chứ không phải là "một phần của từ".
Vì chả lý gì ta lại "lược" chuỗi "Danh anh di" thành "Danh di".
"Lược" là để loại bỏ các TỪ thừa cho câu nó gọn chứ không phải lược để thay nghĩa của câu.
Tất nhiên tôi không khẳng định là chỉ có tôi hiểu được ý của Hải. Ý kiến thôi chứ không áp đặt.
Đúng rồi anh. Vì em áp dụng mấy bài giảng của anh để tập viết pattern nên muốn loại bỏ những từ cà lăm thôi. Thì từ đầu cũng có đề cặp như thế.
......................
Hỏng biết là HuuThangbd có phát hiện lỗi gì mình cũng muốn học hỏi vì Regexp thật sự khó ăn mà.
 
Upvote 0
Hỏng biết là HuuThangbd có phát hiện lỗi gì mình cũng muốn học hỏi vì Regexp thật sự khó ăn mà.
Với Pattern của anh Hải đưa ra
Mã:
[COLOR=#000000][I].Pattern = "\b(\w+)(?:\s+\1)+"[/I][/COLOR]
Thì các trường hợp mà 1 từ được lặp lại với phần đầu của từ kế tiếp sẽ bị thay thế => Lỗi
Ví dụ: Str ="Tran Quan Quang Hai"
 
Upvote 0
Với Pattern của anh Hải đưa ra
Mã:
[COLOR=#000000][I].Pattern = "\b(\w+)(?:\s+\1)+"[/I][/COLOR]
Thì các trường hợp mà 1 từ được lặp lại với phần đầu của từ kế tiếp sẽ bị thay thế => Lỗi
Ví dụ: Str ="Tran Quan Quang Hai"
Chưa trúng thì thêm xíu nữa. Cái này chắc được đó
.Pattern = "\b(\w+)(?:\s+\1)+\b"
 
Upvote 0
Không biết các hàm/ thủ tục dưới đây giúp ích được gì không nhỉ? Mình sưu tầm internet:

Mã:
'Add regular expression functionality using vbscript for fast and easy pattern matching.
Public Function Regexp(strData As String, strPattern As String) As String
    
    Dim oRegexp As Object, oMatches As Object
     
    On Error GoTo Error_Here

    If Len(strData) = 0 Or Len(strPattern) = 0 Then Exit Function
     
    Set oRegexp = CreateObject("vbscript.regexp")
    
    With oRegexp
        .MultiLine = False
        .Global = False
        .IgnoreCase = True
        .Pattern = strPattern
    End With
     
    Set oMatches = oRegexp.Execute(strData)
    Regexp = oMatches(0)

Exit_Here:
    Exit Function
Error_Here:
    Regexp = ""
    Resume Exit_Here
End Function

'--------------------------------------------------------------------------------

Public Function RegexpBln(strData As String, strPattern As String) As Boolean
    RegexpBln = Len(Regexp(strData, strPattern)) > 0
End Function

'--------------------------------------------------------------------------------

'Sample:
Public Sub ClearTags(frm As form)
'Tag property will be cleared if control name matches "txt" followed by a two digit number
'More info: http://www.regular-expressions.info/

    Dim ctl As Control

    For Each ctl In frm.Controls
        If TypeOf ctl Is TextBox Then
            If RegexpBln(ctl.Name, "^txt[0-9][0-9]$") Then
                ctl.Tag = ""
            End If
        End If
    Next ctl

End Sub
 
Upvote 0
Tôi đã đọc chủ để này không biết bao nhiêu lần và mỗi khi đọc đến bài cuối tôi lại tự nhủ "Coi như chưa thấy nó" - đó là bí quyết của tôi đối với những cám dỗ mà mình lực bất tòng tâm.

Hôm nay xem bài này http://www.giaiphapexcel.com/forum/...ấu-xuống-dòng-(Alt-Enter)&p=514244#post514244
Tôi lại chui vào đây với hi vọng sẽ hiểu thêm đoạn code này (những chữ màu đỏ)

Mã:
            With CreateObject("VbScript.Regexp")
                .Global = True
[COLOR=#ff0000]                .MultiLine = True[/COLOR]
                .Pattern =[COLOR=#ff0000] "^.*$"[/COLOR]
                For Each Match In .Execute(sh.Cells(rw, col))
                    i = i + 1
                    Arr(i, col) = Replace(Match, ",", ".")
                Next
            End With
nhưng lại "tẩu hỏa nhập ma" bởi

.Pattern ="\b(\w+)\b([\w\W]*)\b\1\b" .
.Pattern = "\b(\w+)(?:\s+\1)+\b"
.Pattern = ........

Vậy các bạn có thể chú giải giúp tôi ý nghĩa đơn của từng mẫu Pattern được không (ý muốn hỏi "cái gì là cái gì ấy mà" ? để tôi biết nó là cái giống gì mà khoai thế). Thanks !
 
Lần chỉnh sửa cuối:
Upvote 0
nhưng lại "tẩu hỏa nhập ma" bởi

.Pattern ="\b(\w+)\b([\w\W]*)\b\1\b" .
.Pattern = "\b(\w+)(?:\s+\1)+\b"
.Pattern = ........

Vậy các bạn có thể chú giải giúp tôi ý nghĩa đơn của từng mẫu Pattern được không (ý muốn hỏi "cái gì là cái gì ấy mà" ? để tôi biết nó là cái giống gì mà khoai thế). Thanks !

Thế anh đã đọc bài này chưa:
http://www.giaiphapexcel.com/forum/...hử-nghiệm-VBScript-RegExp&p=441883#post441883
Download file Script.chm về xem mới biết \b, \w... vân vân.. là cái gì anh à
 
Upvote 0
Upvote 0
Web KT
Back
Top Bottom