Thử nghiệm VBScript RegExp (1 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

Quang_Hải

Thành viên gạo cội
Tham gia
21/2/09
Bài viết
6,076
Được thích
8,007
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:
Để 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
Ý bạn là tách lấy ký tự AlphaB chăng? Vậy sao không .Pattern = "[^a-zA-Z]" cho khỏe?
 
Upvote 0
Chúng ta cùng khảo sát những ứng dụng cơ bản của VBScript RegExp
Để 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
Bình tĩnh, bình tĩnh. Cái pattern của bạn dùng để tách cái gì?
"Để tách lấy các ký tự"? Nhưng tách lấy "các ký tự" gì? Chữ số hay không chữ số thì phải nói rõ ra chứ "ký tự" thì ai mà hiểu được? Tôi hiểu là tách chữ số rồi thay bằng "", tức xóa.
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ự đó
"không phải là những mẫu tự" có nghĩa là không phải cái gì?
"Khử" là gì? Tôi hiểu là "khử" có nghĩa là tìm các "đoạn" khớp với pattern rồi thay chúng bằng "", tức xóa chúng. Ý của bạn là thế?
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
Không khử triệt để nghĩa là gì? Nếu vd. bạn có chuỗi "12ab_345_678" và có code với pattern như sau - tức không có "_"
Mã:
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
Thì bạn mong muốn nó trả về cái gì? Nếu tôi hiểu ý bạn từ pattern sau là "[\W\d,_]" thì bạn muốn tìm tất cả các chữ số và ký tự "_" rồi xóa chúng. Vậy thì bạn mong đợi cái gì với code ở trên? Mà trước tiên yêu cầu của bạn là gì? Là xóa hết các chữ số và ký tự "_"? Nếu thế thì bạn viết pattern sai chứ tại sao lại "Nhưng không hiểu sao ký tự _ vẫn không được xử lý triệt để"?
Code ở trên trả về "ab__" (2 dấu "_") thì đúng với pattern quá rồi còn gì?
Nếu bạn muốn xóa chữ số và cả ký tự "_" thì pattern là [\d_] hoặc "\d|_".
Mà bạn chú ý là "[\d_]" chứ không phải là "[\d,_]" đâu nhé. Các ký tự trong [...] nối tiếp nhau chứ không có các dấu phân cách chúng đâu nhé. Nếu bạn thêm dấu phẩy "," vào [...] thì vô tình bạn đã thêm vào pattern dấu ",", tức lúc đó là: xóa tất cả các chữ số, ký tự "_" và dấu phẩy, khác với yêu cầu thực của bạn.
Tóm lại bạn nên cho chuỗi cụ thể, miêu tả nó có dạng thế nào. Và nói yêu cầu của bạnn. Tiếp theo bạn có 2 lựa chọn:
1. Hỏi cách viết pattern thế nào
2. Cho 1 code cụ thể với pattern cụ thể và hỏi: Tại sao tôi mong nó trả về thế này thế này mà nó lại trả về thế kia thế kia? Tôi sai ở đâu.
Phải rõ ràng như thế mới thảo luận được. Vấn đề phải được nêu rõ, yêu cầu cụ thể thì mới thảo luận được.
 
Lần chỉnh sửa cuối:
Upvote 0
Theo hướng dẫn của anh NDU và anh Siwtom, mình tự đưa ra kết luận cho bản thân thế này

Nếu ta cần xử lý 1 chuỗi để lấy ra 1 chuỗi chỉ duy nhất là các chữ cái từ a-Z, thì Pattern này là hợp lý nhất

PHP:
    .Pattern = "[^a-zA-Z]"

Nhưng có điều là sau khi xử lý chuỗi không có cái dấu tiếng việt nào cả

Nhưng mình làm thế này thì có thể giữ lại dấu tiếng việt, nhưng phải chỉ định những gì cần xóa
Có điều mình không hiểu tại sao muốn chỉ định xóa cái dấu nhấy kép thì phải nhập 2 cái nháy thế này "" thì code mới chịu. Các anh xem và cho ý kiến giúp

PHP:
   .Pattern = "\d|_|'|-|""|,|"
 
Upvote 0
Có điều mình không hiểu tại sao muốn chỉ định xóa cái dấu nhấy kép thì phải nhập 2 cái nháy thế này "" thì code mới chịu. Các anh xem và cho ý kiến giúp

PHP:
   .Pattern = "\d|_|'|-|""|,|"

Dùng 1 ví dụ khác nhé!
Ta có công thức =IF(A1="", "", "A1)
Giờ nếu như ta viết code VBA để chèn công thức trên vào cell B1 thì bạn sẽ viết thế nào? Từ đó suy ra cái bạn thắc mắc
 
Upvote 0
Giờ chúng ta có 1 chuỗi thế này

12345sadsa12345asdasd

Và chúng ta muốn cộng 2 dãy số bên trong lại với nhau để có kết quả là 24690
Mình dùng code thế này thì cộng lại được, nhưng liệu có cách nào ngắn gọn hơn không?
Có cách nào kết hợp 2 lần .Pattern thành 1 hay không?
PHP:
Sub Congso_RegExp()
Dim i, kq
  With CreateObject("VBScript.RegExp")
    For i = 1 To 5
      .Global = True
      .Pattern = "\D"
      kq = Application.Trim(.Replace(Cells(i, 1), " "))
      .Pattern = " "
      Cells(i, 2) = Evaluate(.Replace(kq, "+"))
    Next
  End With
End Sub
 
Upvote 0
Giờ chúng ta có 1 chuỗi thế này

12345sadsa12345asdasd

Và chúng ta muốn cộng 2 dãy số bên trong lại với nhau để có kết quả là 24690
Mình dùng code thế này thì cộng lại được, nhưng liệu có cách nào ngắn gọn hơn không?
Có cách nào kết hợp 2 lần .Pattern thành 1 hay không?
PHP:
Sub Congso_RegExp()
Dim i, kq
  With CreateObject("VBScript.RegExp")
    For i = 1 To 5
      .Global = True
      .Pattern = "\D"
      kq = Application.Trim(.Replace(Cells(i, 1), " "))
      .Pattern = " "
      Cells(i, 2) = Evaluate(.Replace(kq, "+"))
    Next
  End With
End Sub
Nghĩ được cái này:
PHP:
Sub Congso_RegExp()
  Dim i, kq
  With CreateObject("VBScript.RegExp")
    For i = 1 To 5
      .Global = True
      .Pattern = "\D"
      kq = .Replace(Cells(i, 1), "+0")
      Cells(i, 2) = Evaluate(kq)
    Next
  End With
End Sub
Góp ý: Một là cho file lên, Hai là viết thành Function cho dễ test bạn à
 
Upvote 0
Giờ chúng ta có 1 chuỗi thế này

12345sadsa12345asdasd

Và chúng ta muốn cộng 2 dãy số bên trong lại với nhau để có kết quả là 24690
Mình dùng code thế này thì cộng lại được, nhưng liệu có cách nào ngắn gọn hơn không?
Có cách nào kết hợp 2 lần .Pattern thành 1 hay không?
PHP:
Sub Congso_RegExp()
Dim i, kq
  With CreateObject("VBScript.RegExp")
    For i = 1 To 5
      .Global = True
      .Pattern = "\D"
      kq = Application.Trim(.Replace(Cells(i, 1), " "))
      .Pattern = " "
      Cells(i, 2) = Evaluate(.Replace(kq, "+"))
    Next
  End With
End Sub
Ngắn gọn hơn hay không thì mình ....cóc có biết, nhưng với đề bài này & sử dụng RegExp thì mình làm thế này:
Mã:
Public Function Tong(Cll As Range) As Long
    Dim Re As Object, A, KetQua, Tim, ReTim
    Set Re = CreateObject("vbscript.regexp")
    With Re
        .Global = True
        .Pattern = "\d+"
       Set ReTim = Re.Execute(Cll)
    End With
            For Each Tim In ReTim
                KetQua = KetQua + Val(Tim.Value)
            Next Tim
    Tong = KetQua
End Function
Híc
 

File đính kèm

Upvote 0
Anh Cò và anh NDU giải thích ý nghĩa của mấy cái này dùm em

"+0"
"\d+"
.Execute(Cll)
 
Upvote 0
Anh Cò và anh NDU giải thích ý nghĩa của mấy cái này dùm em


"\d+"
.Execute(Cll)
Mắc cười quá, anh & chú em đều là dân học.......mò sao lại hỏi câu đó:
1- "\d+": sao không bỏ dấu cộng đi coi code nó làm cái quái gì & kết quả ra răng thì hiểu ngay thôi mà, còn nếu hổng hiểu thì....từ từ sẽ hiểu
2- Execute: câu này mình chơi ngôn ngữ quốc tế với nhau nhé:
Execute là một trong 3 Methods của RegExp, 2 thằng kia là Replace & Test. Đại khái như thế này: Execute(Cll) thực hiện lệnh so sánh xem chuỗi Cll có chứa em nào khớp với thằng Pattern hay không, nếu có kết quả trả về là một mảng, muốn lấy em nào thì duyệt qua mảng í để lấy
Híc
 
Upvote 0
Execute(Cll) thực hiện lệnh so sánh xem chuỗi Cll có chứa em nào khớp với thằng Pattern hay không, nếu có kết quả trả về là một mảng, muốn lấy em nào thì duyệt qua mảng í để lấy
Híc
Hổng phải MẢNG anh à! Nó là Collection ----> Là 1 mớ hổn độn chứ không có chiều như mảng
 
Upvote 0
Hổng phải MẢNG anh à! Nó là Collection ----> Là 1 mớ hổn độn chứ không có chiều như mảng
Hihi, thì quen gọi như thế, trong đó nó có cả một đống "hầm bà lằng xắng cấu" cho ta muốn lấy gì cũng được
Thanks Thầy Ndu
 
Upvote 0
"\d+" : có nghĩa là ký tự số trong "chuỗi mẫu (pattern)" có thể xuất hiện 1 hoặc nhiều lần nhưng ít nhất phải xuất hiện 1 lần.
 
Upvote 0
Tiếp tục chủ đề này với hàm tách tên
Trước đây mình thường dùng hàm này để tách tên

PHP:
Function tachten(cell As Range)
   tachten = Right(cell, Len(cell) - InStrRev(cell, " "))
End Function

Nhưng thấy cách dùng này của RegExp cũng hay nên up lên để mọi người tham khảo

PHP:
Function tachten(cell As Range)
   With CreateObject("vbscript.regexp")
      .Global = True
      .Pattern = ".* "
      tachten = .Replace(cell, "")
   End With
End Function

Ứng dụng cách này mình cũng có thể loại bỏ 1 chuỗi ký tự trước 1 ký tự nào đó
Ví dụ ta có chuỗi "Nguyen, Van Minh" <ami8688@gmail.com>,
Dùng hàm này có thể loại bỏ "Nguyen, Van Minh" ra khỏi chuỗi để lấy ra địa chỉ mail

PHP:
Function tach(cell As Range)
   With CreateObject("vbscript.regexp")
      .Global = True
      .Pattern = ".*"" "
      tach = .Replace(cell, "")
   End With
End Function
 
Lần chỉnh sửa cuối:
Upvote 0
Ví dụ nha, trong 1 cell có 2 đk cần thay thế, chuỗi là: Hoang:Trong=Nghia

Tôi muốn kết quả là Hoang Trong Nghia thì phải dùng Pattern như thế nào?

Chẳng lẽ phải dùng đến 2 lần Pattern?

R = "Hoang:Trong=Nghia"
With CreateObject("vbscript.regexp")
.Global = True
.Pattern = ":"
R= .Replace(R), " ")
.Pattern = "="
R= .Replace(R, " ")
End With
 
Lần chỉnh sửa cuối:
Upvote 1
Ví dụ nha, trong 1 cell có 2 đk cần thay thế, chuỗi là: Hoang:Trong=Nghia

Tôi muốn kết quả là Hoang Trong Nghia thì phải dùng Pattern như thế nào?

Chẳng lẽ phải dùng đến 2 lần Pattern?

R = "Hoang:Trong=Nghia"
With CreateObject("vbscript.regexp")
.Global = True
.Pattern = ":"
R= .Replace(R), " ")
.Pattern = "="
R= .Replace(R, " ")
End With
Thì vầy thôi: .Pattern = "[:=]"
Cho phép tìm nhiều từ khóa cùng lúc mà
 
Upvote 0
Ví dụ nha, trong 1 cell có 2 đk cần thay thế, chuỗi là: Hoang:Trong=Nghia

Tôi muốn kết quả là Hoang Trong Nghia thì phải dùng Pattern như thế nào?

Chẳng lẽ phải dùng đến 2 lần Pattern?

R = "Hoang:Trong=Nghia"
With CreateObject("vbscript.regexp")
.Global = True
.Pattern = ":"
R= .Replace(R), " ")
.Pattern = "="
R= .Replace(R, " ")
End With
Muốn bỏ mấy thằng không phải a-z, 0-9 thì thử dùng cái này xem sao:
.Pattern = "\W"
--------------
Ý cha!
Gặp mấy thằng chữ Việt có dấu là tèo luôn, "hổng được gồi".
 
Lần chỉnh sửa cuối:
Upvote 0
Thì vầy thôi: .Pattern = "[:=]"
Cho phép tìm nhiều từ khóa cùng lúc mà

Bây giờ có chuỗi là:

: A+B=C

Mình muốn loại bỏ những thứ màu xanh đi, thì Pattern có làm được 1 lần không? Dĩ nhiên với C là bất kỳ sau dấu =

Theo em nghĩ sẽ phải làm 2 lần pattern mới giải quyết được!

R = ": A+B=C"
With CreateObject("vbscript.regexp")
.Global = True
.Pattern = ": "
R= .Replace(R), "")
.Pattern = "=.*"
R= .Replace(R, "")
End With
 
Lần chỉnh sửa cuối:
Upvote 0
Bây giờ có chuỗi là:

: A+B=C

Mình muốn loại bỏ những thứ màu xanh đi, thì Pattern có làm được 1 lần không? Dĩ nhiên với C là bất kỳ sau dấu =

Theo em nghĩ sẽ phải làm 2 lần pattern mới giải quyết được!

R = ": A+B=C"
With CreateObject("vbscript.regexp")
.Global = True
.Pattern = ": "
R= .Replace(R), "")
.Pattern = "=.*"
R= .Replace(R, "")
End With

Hình nhử vầy nè anh ơi

With CreateObject("vbscript.regexp")
.Global = True
.Pattern = "=.*|:"
R = .Replace(R, "")
End With
 
Upvote 0
Hình nhử vầy nè anh ơi

With CreateObject("vbscript.regexp")
.Global = True
.Pattern = "=.*|:"
R = .Replace(R, "")
End With

Hiểu rồi, vậy dấu phân cách của nó ở đây: .Pattern = "=.*|:"

Chủ yếu mình muốn tìm là nó đấy! Cám ơn QuangHai nhiều nhé!
 
Upvote 0
Cho hỏi thêm 1 vấn đề:

Nếu có chuỗi là: Hoang Hoang Trong Nghia

Tôi muốn loại bỏ chữ Hoang đầu, có nghĩa rằng chuỗi nó gặp lần đầu thì nó sẽ loại ra, còn những chữ sau nó lướt qua, giống như cấu trúc của hàm Replace (phần count) của VBA vậy. Ta phải làm như thế nào?

Mở Immediate (Ctrl+G) và gõ cái này vào sẽ thấy hàm Replace của VBA nó hoạt động:

?Replace("Hoang Hoang Trong Nghia", "Hoang ", "", , 1)
 
Lần chỉnh sửa cuối:
Upvote 0
Hiểu rồi, vậy dấu phân cách của nó ở đây: .Pattern = "=.*|:"

Chủ yếu mình muốn tìm là nó đấy! Cám ơn QuangHai nhiều nhé!

Nói thêm: cái dấu | hổng phải là dấu phân cách. Nó có ý nghĩa là OR ---> X|Y nghĩa là Match X OR Match Y
Có vẻ như Nghĩa đang "dự tính" làm bài toán có liên quan đến dự toán đây (biến biểu thức thành giá trị)
 
Upvote 0
Nói thêm: cái dấu | hổng phải là dấu phân cách. Nó có ý nghĩa là OR ---> X|Y nghĩa là Match X OR Match Y
Có vẻ như Nghĩa đang "dự tính" làm bài toán có liên quan đến dự toán đây (biến biểu thức thành giá trị)

Vậy nếu nó là OR thì AND của nó là gì ạ?
 
Upvote 0
Cho hỏi thêm 1 vấn đề:

Nếu có chuỗi là: Hoang Hoang Trong Nghia

Tôi muốn loại bỏ chữ Hoang đầu, có nghĩa rằng chuỗi nó gặp lần đầu thì nó sẽ loại ra, còn những chữ sau nó lướt qua, giống như cấu trúc của hàm Replace (phần count) của VBA vậy. Ta phải làm như thế nào?

Mở Immediate (Ctrl+G) và gõ cái này vào sẽ thấy hàm Replace của VBA nó hoạt động:

?Replace("Hoang Hoang Trong Nghia", "Hoang ", "", , 1)
Làm thế này
Mã:
Dim R
With CreateObject("vbscript.regexp")
.Global = False
.Pattern = "[A-Za-z]+\s"
R = .Replace([A1], "")
End With
Với [A1] chứa chuỗi
Bài toán diễn giải công thức mà chơi em này thì tuyệt vời
Đề bài là dữ liệu không dấu tiếng Việt, nếu có dấu phải chơi kiểu khác nhé
Vậy nếu nó là OR thì AND của nó là gì ạ?
Không có And, tức là muốn Pattern thế nào thì cứ thế ....mà phang tới tới thôi
Híc
 
Lần chỉnh sửa cuối:
Upvote 0
Làm thế này
Mã:
Dim R
With CreateObject("vbscript.regexp")
.Global = False
.Pattern = "[A-Za-z]+\s"
R = .Replace([A1], "")
End With
Với [A1] chứa chuỗi
Bài toán diễn giải công thức mà chơi em này thì tuyệt vời

Hay lắm, nhưng diễn giải cái chỗ .Pattern = "[A-Za-z]+\s" thì sẽ như thế nào?

[A-Za-z]: Ký tự từ A đến Z (hoa và thường)

Còn cái này là gì? +\s
 
Upvote 0
Vậy nếu nó là OR thì AND của nó là gì ạ?

Hỏi gì vậy trời?
X AND Y thì viết là XY thôi
-------------------
Làm thế này
Mã:
Dim R
With CreateObject("vbscript.regexp")
.Global = False
[COLOR=#ff0000][B].Pattern = "[A-Za-z]+\s"[/B][/COLOR]
R = .Replace([A1], "")
End With
Với [A1] chứa chuỗi
Vầy cũng được nè: .Pattern = "[\w]{1,}"
Ẹc... Ẹc...
 
Lần chỉnh sửa cuối:
Upvote 0
Hay lắm, nhưng diễn giải cái chỗ .Pattern = "[A-Za-z]+\s" thì sẽ như thế nào?

[A-Za-z]: Ký tự từ A đến Z (hoa và thường)

Còn cái này là gì? +\s
Cái đó là cái ....khoảng trắng, nếu không có nó thì kết quả sẽ có 1 em trắng trẻo ở đầu cell
Híc
Vầy cũng được nè: .Pattern = "[\w]{1,}"
Ẹc... Ẹc...
Nói chung cái Pattern có nhiều cách viết và cũng.....cực khó
Hình như chỉ có bạn siwtom là rành cái này
 
Lần chỉnh sửa cuối:
Upvote 0
Hỏi gì vậy trời?
X AND Y thì viết là XY thôi
-------------------

Vầy cũng được nè: .Pattern = "[\w]{1,}"
Ẹc... Ẹc...

Có cảm giác điều kiện cũng giống toán tử LIKE nhỉ? Tuy nhiên có dấu tiếng Việt UNI chắc phải có gì khác chứ nhỉ?
 
Upvote 0
Upvote 0

File đính kèm

  • Picture1.jpg
    Picture1.jpg
    35.9 KB · Đọc: 216
Upvote 0
Toàn bộ file CHM đều bị vậy hay chỉ có file này thôi?
Nghĩa search googe từ khóa CHM file error "Navigation to the webpage was canceled" xem


OK! đã làm cho nó đọc được! Mới thực hiện ở bước 2

Step 1:


a. Click Start, type cmd, right-click and select Run as administrator.
b. Enter the following command and hit Enter:

regsvr32 hhctrl.ocx

After getting the success message "DllRegisterServer in hhctrl.ocx succeeded", try to open your CHM file again.

Step 2:

If you are sure that the help documentation is from a trusted source, try and open it by following the below steps:

a. Right-click the CHM file and click “Properties”.
b. In the “General” tab of the “Properties” dialog box, click the “Unblock” button under “Security” at the bottom.
c. Click “Apply” and “OK” to save the settings.

Try opening the .CHM files and check if that fixes the issue.

Step 3: Perform a System File Checker (SFC) scan

SFC toolscans system files and replaces incorrect versions of the system files by using the correct versions.
 
Upvote 0
Tôi hiểu là Nghĩa muốn loại từ khi nó bị lặp ở vị trí bất kỳ (vì ở ngay đầu thì dễ quá)? Nếu thế thì pattern của concogia không làm được. Vì ở vd. cụ thể thì Hoang được lặp mà nó lại đứng đầu. Nếu có "Trong Nghia Hoang Hoang" thì ta sẽ được "Nghia Hoang Hoang"
Nhìn pattern thì biết nó luôn loại 1 (vì Global = FALSE) từ đứng ởđầu chuỗi.

Câu hỏi:
Loại từ - tức cụm ký tự thuộc [A-Za-z_] - được lặp lại liền nhau.

Chuỗi tổng quát:
"nhiều từ (1 hoặc nhiều dấu cách) (cụm abc...xyz) (1 hoặc nhiều dấu cách) (cụm abc...xyz) (1 hoặc nhiều dấu cách) nhiều từ"

Yêu lầu: loại 1 (cụm abc...xyz) - (cụm abc...xyz) là một từ nào đó
 
Upvote 0
Tôi hiểu là Nghĩa muốn loại từ khi nó bị lặp ở vị trí bất kỳ (vì ở ngay đầu thì dễ quá)? Nếu thế thì pattern của concogia không làm được. Vì ở vd. cụ thể thì Hoang được lặp mà nó lại đứng đầu. Nếu có "Trong Nghia Hoang Hoang" thì ta sẽ được "Nghia Hoang Hoang"
Nhìn pattern thì biết nó luôn loại 1 (vì Global = FALSE) từ đứng ởđầu chuỗi.

Câu hỏi:
Loại từ - tức cụm ký tự thuộc [A-Za-z_] - được lặp lại liền nhau.

Chuỗi tổng quát:
"nhiều từ (1 hoặc nhiều dấu cách) (cụm abc...xyz) (1 hoặc nhiều dấu cách) (cụm abc...xyz) (1 hoặc nhiều dấu cách) nhiều từ"

Yêu lầu: loại 1 (cụm abc...xyz) - (cụm abc...xyz) là một từ nào đó
Vậy thì anh biểu diễn luôn đi. Nói thiệt là anh em đang quá trình nghiên cứu chứ không hiểu sâu đâu!
 
Upvote 0
Vậy thì anh biểu diễn luôn đi. Nói thiệt là anh em đang quá trình nghiên cứu chứ không hiểu sâu đâu!

Tuấn nói có vẻ dễ nhỉ. Nhiều khi thuộc lòng một vai mà vẫn có thể có lần sẩy ra sự cố để rồi cà chua thối trứng thối biết bay đi đâu.
Vẫn biết phải có đinh và búa, và phải gõ vào cái đầu "tòe tòe" này thế mà không ít lần vẫn chọt vào ngón tay.
Mỗi ký tự trong cụm là chữ cái, chữ số hoặc "_" vậy paterrn cho cum1 = (cụm abc...xyz) có lẽ là "\b\w+\b". Pattern cho cum2 = (cụm abc...xyz) cũng là "\b\w+\b". Vấn đề còn lại chỉ là trong kết quả trả về thì cum1 và cum2 là y như nhau. Và phải tìm tất cả các "cặp" từ lặp như thế.
vd. chuỗi "ngay mai mai ta di ca ca phe nhe em em nhe" (em nó nói lắp, thông cảm nhé) thì kết quả là "ngay mai ta di ca phe nhe em nhe"
 
Upvote 0
Tuấn nói có vẻ dễ nhỉ. Nhiều khi thuộc lòng một vai mà vẫn có thể có lần sẩy ra sự cố để rồi cà chua thối trứng thối biết bay đi đâu.
Vẫn biết phải có đinh và búa, và phải gõ vào cái đầu "tòe tòe" này thế mà không ít lần vẫn chọt vào ngón tay.
Mỗi ký tự trong cụm là chữ cái, chữ số hoặc "_" vậy paterrn cho cum1 = (cụm abc...xyz) có lẽ là "\b\w+\b". Pattern cho cum2 = (cụm abc...xyz) cũng là "\b\w+\b". Vấn đề còn lại chỉ là trong kết quả trả về thì cum1 và cum2 là y như nhau. Và phải tìm tất cả các "cặp" từ lặp như thế.
vd. chuỗi "ngay mai mai ta di ca ca phe nhe em em nhe" (em nó nói lắp, thông cảm nhé) thì kết quả là "ngay mai ta di ca phe nhe em nhe"

Sao chả ai có ý kiến gì vậy? Ít ra nếu ai đó hỏi thêm chi tiết hay đề nghị pattern nào đó thì dù đúng dù sai cũng biết được có người theo dõi chủ đề. Còn không chả biết "khán giả" đang ngủ gật hết hay thậm chí chả có ai cả.
Nhưng thôi, tôi đề nghị một pattern. Tôi cũng "nhìn kỹ" RegExp thời gian gần đây thôi nên có thể hiểu không đúng. Trước đó tôi cũng có biết nhưng chỉ là: mặt mũi nó thế nào, nó dùng làm gì, thế thôi.
----------
Về câu hỏi thì ta dùng Backreferences thôi. Nói nôm na thì nếu có một đoạn trong pattern được đóng trong cặp ngoặc () thì nó được ghi nhớ (có ngoại lệ, không phải cứ đoạn nào nằm trong ngoặc là Backreferences) để:
1. Trong phần tiếp theo của pattern có thể truy cập ngược tới "chỗ" được ghi nhớ trước đó. Các cụm trong ngoặc được nhớ theo thứ tự và nếu muốn truy cập tới "cụm" n thì viết \n, với n = 1, 2, ...
Nên nhớ là viết \1 không phải với mục đích để gõ ít đi. \1 có nghĩa là tại "chỗ đó" phải có nội dung trong kết quả tìm được "y hệt" như đoạn trong ngoặc đầu tiên. Nếu đoạn trong ngoặc là cụ thể (pho) thì chả cần gõ \1 làm gì mà gõ luôn "pho" tại đó, và cũng chả cần cho "pho" đầu tiên vào ngoặc. Nhưng có những tình huống khi ta chỉ có trong ngoặc "dạng" thôi thì chỗ "kia" ta không biết gõ thế nào để nó "y hệt" như chỗ trong ngoặc. Lúc đó ta dùng \1.
vd. pattern "(...)abc(...)defgh\2xyz\1"
Thì nếu tìm thấy thì trong mỗi kết quả trả về tại chỗ mầu đỏ và chỗ \1 phải có 2 cụm từ "y hệt" nhau, tại chỗ mầu xanh và \2 phải có 2 cụm từ "y hệt" nhau.
2. Ở trên ta dùng \1, \2, ... để truy cập tới một đoạn trong pattern đã có trước đó và được ghi nhớ - do đặt trong ngoặc "()" - trong phần tiếp theo của pattern.
Nhưng ta cũng có thể dùng những đoạn ghi nhớ trong phương thức Replace, nhưng ghi là $1, $2, ...
Vd. với Pattern = "([a-z\s]+)abc([a-z\s]+)defgh\2xyz\1" và chuỗi:
s = "toi anabccomdefghcomxyztoi an hic hic anh ay nhauabcthit chodefghthit choxyzanh ay nhau ec ec"
Nếu ta có kq = .Replace(s, "$1 $2")
thì kq = "toi an com hic hic anh ay nhau thit cho ec ec"
Tại sao thế? Ta có 2 đoạn tìm thấy trong chuỗi s là:
1. "toi anabccomdefghcomxyztoi an" trong đó $1 = "toi an", $2 = "com"
Replace đổi đoạn này trong chuỗi s thành "$1 $2" = "toi an com"
2. "anh ay nhauabcthit chodefghthit choxyzanh ay nhau" trong đó $1 = "anh ay nhau", $2 = "thit cho"
Replace đổi đoạn này trong chuỗi s thành "$1 $2" = "anh ay nhau thit cho"
Kết quả: "toi anabccomdefghcomxyztoi an hic hic anh ay nhauabcthit chodefghthit choxyzanh ay nhau ec ec" bị đổi thành "toi an com hic hic anh ay nhau thit cho ec ec"
Mã:
Sub test()
Dim s As String, re As Object
    s = "toi anabccomdefghcomxyztoi an hic hic anh ay nhauabcthit chodefghthit choxyzanh ay nhau ec ec"
    
    Set re = CreateObject("VBScript.RegExp")
    re.Global = True
    re.IgnoreCase = True
    re.pattern = "([a-z\s]+)abc([a-z\s]+)defgh\2xyz\1"
    If re.test(s) Then
        s = re.replace(s, "$1 $2")
    End If
    Debug.Print s
End Sub
-----------
Bây giờ thì dễ rồi

Mã:
Sub huhu()
Dim s As String, re As Object
    s = "ngay mai mai ta di ca ca phe nhe em em nhe"
    
    Set re = CreateObject("VBScript.RegExp")
    re.Global = True
    re.IgnoreCase = True
    re.pattern = "(\b\w+\b)\s+\1"
    If re.test(s) Then
        s = re.replace(s, "$1")
    End If
    Debug.Print s
End Sub

----------------------
Nếu ta muốn xử lý tình huống "từ" được lặp lại liên tiếp 2 hoặc > 2 lần mà ta muốn viết 1 pattern thì
Mã:
Sub huhu()
Dim s As String, re As Object
    s = "ngay mai mai mai mai mai ta di ca ca ca ca phe nhe em em em em em em nhe"
    
    Set re = CreateObject("VBScript.RegExp")
    re.Global = True
    re.IgnoreCase = True
    re.pattern = "(\b\w+\b)\s+(\1\s)*\1"
    If re.test(s) Then
        s = re.replace(s, "$1")
    End If
    Debug.Print s
End Sub

Kết quả s = "ngay mai ta di ca phe nhe em nhe"

Mọi người kiểm tra xem có lỗi không nhé
 
Lần chỉnh sửa cuối:
Upvote 0
Sao chả ai có ý kiến gì vậy? Ít ra nếu ai đó hỏi thêm chi tiết hay đề nghị pattern nào đó thì dù đúng dù sai cũng biết được có người theo dõi chủ đề. Còn không chả biết "khán giả" đang ngủ gật hết hay thậm chí chả có ai cả.
Nhưng thôi, tôi đề nghị một pattern. Tôi cũng "nhìn kỹ" RegExp thời gian gần đây thôi nên có thể hiểu không đúng. Trước đó tôi cũng có biết nhưng chỉ là: mặt mũi nó thế nào, nó dùng làm gì, thế thôi.

Má ơi... nó lằng nhằng như.. mì tôm cua ấy ---> Anh bào ai mà có Ý KIẾN với Ý CÒ gì được đây?
Ẹc... Ec...
Chỉ chở để CHIÊM NGƯỞNG thôi anh à!
 
Upvote 0
RegExp - phần tiếp theo

Ta định nghĩa khái niệm cho bài tập:
Ta gọi các chuỗi gồm chữ cái, chữ số, "_" và dấu cách mà ký tự đầu và cuối thuộc \w (chữ cái, chữ số, "_"), và phần đầu và phần cuối y hệt nhau là các chuỗi dạng A.

vd. "11", "1234512", "abc23dea", "anh oi la anh" là các chuỗi dạng A.
--------------------
Cho một chuỗi str, trong bài tập này ta chỉ xét các đoạn dạng A mà hoặc ký tự đầu (ký tự cuối) của nó cũng là ký tự đầu (ký tự cuối) của str hoặc trước ký tự đầu (sau ký tự cuối) của nó là dấu cách (xét trong chuỗi str).

vd. str = "1234512" thì ta chỉ xét 1 đoạn duy nhất là chính str. Đoạn "123451" ta không xét vì sau ký tự cuối (ký tự 1) của đoạn này thì trong str có ký tự 2 (<> dấu cách). Tương tự ta không xét đoạn "234512" mặc dù có dạng A.

Hãy viết pattern tìm ra các chuỗi có dạng đang xét ngắn nhất có thể.
---------
Thôi, cho chuỗi cụ thể:
s = "11 1234512 abc23dea anh oi la anh 11
Kết quả là:
11, 1234512, abc23dea, anh oi la
 
Lần chỉnh sửa cuối:
Upvote 0
- Thưa bác siwtom vấn đề RegExp quả là khó thật đấy, nhưng chắc chắn sẽ rất hữu ích (mặc dù còn phải tìm hiểu dài dài). Vậy bác có thể giải đáp câu đố trong bài #44 được không ạ và nếu bác có "bài giảng" như trên thì hay quá.(2 tháng rồi chưa có ai giải cả)
- Bác cho dhn46 hỏi: với bài #42, #44 sau khi đánh dấu được các chuỗi $1, $2... thì có cách nào để trích xuất $1$2 không ạ. Ví dụ với bài toán yêu cầu lọc ký tự trùng trong 1 dãy số nếu ứng dụng được cái này thì không cần Dic, không cần vòng lặp
Tks GPE!
 
Upvote 0
- Thưa bác siwtom vấn đề RegExp quả là khó thật đấy, nhưng chắc chắn sẽ rất hữu ích (mặc dù còn phải tìm hiểu dài dài). Vậy bác có thể giải đáp câu đố trong bài #44 được không ạ và nếu bác có "bài giảng" như trên thì hay quá.(2 tháng rồi chưa có ai giải cả)
- Bác cho dhn46 hỏi: với bài #42, #44 sau khi đánh dấu được các chuỗi $1, $2... thì có cách nào để trích xuất $1$2 không ạ. Ví dụ với bài toán yêu cầu lọc ký tự trùng trong 1 dãy số nếu ứng dụng được cái này thì không cần Dic, không cần vòng lặp
Tks GPE!

Khoảng thời gian đó tôi có viết một bài nói đầy đủ về Backreferences và mấy kiểu pattern nhưng để một thời gian thấy chả ai đọc chả ai có ý kiến nên tôi xóa đi.
Chả ai nhờ, chả ai yêu cầu mà tự dưng viết rồi chả ai đọc tôi thấy mình vô duyên quá.
Trước khi xóa tôi có lưu lại ở dạng HTML. Nếu bạn cần thì tôi có thể gửi vào tin nhắn cho bạn.
 
Upvote 0
Vâng thế thì hay quá, dạ cảm ơn bác nhiều. Dhn46 ngồi voọc mấy cái này mà không có đáp án. Cảm ơn bác ạ!
 
Upvote 0
Anh chàng khởi nghiệp (anh QuangHaixxxx) giám đốc đi đâu mất, tại sao tất cả sự nghiệp công việc điều bỏ ngõ hết, 1 mình cố vấn switom lo hết làm sao được, trở lại lo tiếp công việc mình đi chứ:google_lt:
máy bài đầu xem thì mely qua càng về sau đầu tóc dựng cả lên !~` :evil2: <đúng là bãi rốt mênh mong học mãi mà vẫn chưa hết+-+-+-+>
 
Upvote 0
Để tách tên mình dùng Pattern này
PHP:
Function ten(cell As Range)
   With CreateObject("vbscript.regexp")
      .Global = True
      .Pattern = ".*\s"
      ten = .Replace(Trim(cell), "")
   End With
End Function
Để tách lấy họ mình dùng Pattern này
PHP:
Function ho(cell As Range)
   With CreateObject("vbscript.regexp")
      .Global = True
      .Pattern = "\s.*"
      ho = .Replace(Trim(cell), "")
   End With
End Function
Xin hỏi các anh chị ngoài cách dưới đây có cách nào dùng 1 Pattern để lấy được các ký tự bên trong của dấu cách đầu và dấu cách cuối để tách phần tên lót ra hay không?
PHP:
Function tenlot(cell As Range)
Dim ho As String, ten As String
   With CreateObject("vbscript.regexp")
      .Global = True
      .Pattern = ".*\s"
      ten = .Replace(Trim(cell), "")
      .Pattern = "\s.*"
      ho = .Replace(Trim(cell), "")
      tenlot = Application.Trim(Replace(Replace(cell, ho, ""), ten, ""))
   End With
End Function
 
Upvote 0
Để tách tên mình dùng Pattern này
PHP:
Function ten(cell As Range)
   With CreateObject("vbscript.regexp")
      .Global = True
      .Pattern = ".*\s"
      ten = .Replace(Trim(cell), "")
   End With
End Function
Để tách lấy họ mình dùng Pattern này
PHP:
Function ho(cell As Range)
   With CreateObject("vbscript.regexp")
      .Global = True
      .Pattern = "\s.*"
      ho = .Replace(Trim(cell), "")
   End With
End Function
Xin hỏi các anh chị ngoài cách dưới đây có cách nào dùng 1 Pattern để lấy được các ký tự bên trong của dấu cách đầu và dấu cách cuối để tách phần tên lót ra hay không?
PHP:
Function tenlot(cell As Range)
Dim ho As String, ten As String
   With CreateObject("vbscript.regexp")
      .Global = True
      .Pattern = ".*\s"
      ten = .Replace(Trim(cell), "")
      .Pattern = "\s.*"
      ho = .Replace(Trim(cell), "")
      tenlot = Application.Trim(Replace(Replace(cell, ho, ""), ten, ""))
   End With
End Function

Chưa cần suy nghĩ kỹ đã có 1 ví dụ
[GPECODE=vb]
Function tenlot(cell As Range)
With CreateObject("vbscript.regexp")
.Global = True
.Pattern = "^[^\s]+|[^\s]+$"
tenlot = Trim(.Replace(Trim(cell), ""))
End With
End Function
[/GPECODE]

hoặc

[GPECODE=vb]
Function tenlot1(cell As Range) As String
On Error Resume Next
With CreateObject("vbscript.regexp")
.Pattern = "\s.+\s"
tenlot1 = Trim(.Execute(Trim(cell)).Item(0).Value)
End With
End Function
[/GPECODE]

------------------
Ái chà.
Dạng 2 viết xong gửi lên mới thấy là giống cách của dhn46.
Coi như không tính cách 2.
 
Lần chỉnh sửa cuối:
Upvote 0
Voọc chút tài liệu quý của bác Siwtom dhn46 cũng tham gia 1 chút
Mã:
Function tenlot(cell As Range)
   With CreateObject("vbscript.regexp")
      .Pattern = "\s\D+\s"
       Set matches = .Execute(cell)
       tenlot = Trim(matches.Item(0))
    End With
End Function
 
Upvote 0
Voọc chút tài liệu quý của bác Siwtom dhn46 cũng tham gia 1 chút
Mã:
Function tenlot(cell As Range)
   With CreateObject("vbscript.regexp")
      .Pattern = "\s\D+\s"
       Set matches = .Execute(cell)
       tenlot = Trim(matches.Item(0))
    End With
End Function

Phải bẫy lỗi dhn46 ạ. Vì nếu chỉ có Họ và Tên - vd. Đỗ Mười - thì matches = Nothing
 
Upvote 0
Xin hỏi các anh chị ngoài cách dưới đây có cách nào dùng 1 Pattern để lấy được các ký tự bên trong của dấu cách đầu và dấu cách cuối để tách phần tên lót ra hay không?
PHP:
Function tenlot(cell As Range)
Dim ho As String, ten As String
   With CreateObject("vbscript.regexp")
      .Global = True
      .Pattern = ".*\s"
      ten = .Replace(Trim(cell), "")
      .Pattern = "\s.*"
      ho = .Replace(Trim(cell), "")
      tenlot = Application.Trim(Replace(Replace(cell, ho, ""), ten, ""))
   End With
End Function
Thuật toán của anh Hải có một vài chỗ chưa đúng. Do sử dụng phương thức Replace nên nếu rơi vào một trong các trường hợp sau đây kết quả sẽ không đúng:
1. Họ là chuỗi con của Tên ( Thị n)
2. Họ là chuỗi con của tên lót (Hồ Thị Hồng Hà)
3. Tên là chuỗi con của tên lót (Nguyễn Thị Thanh Thanh)

Tôi cũng viết thử một hàm 3 trong 1. Có thể tách họ, tên lót, tên.
[gpecode=vb]Function TachTen(Str As String, Optional Op As Long = 3)
With CreateObject("vbscript.regexp")
.Global = True
.Pattern = "(\S+)( .+ | )(\S+$)"
TachTen = Trim(.Execute(Trim(Str))(0).SubMatches(Op - 1))
End With
End Function[/gpecode]
 
Upvote 0
Vbscript.RegExp quả là hay, với những bài toán tưởng chừng phải dùng vòng lặp duyệt toàn bộ mảng(chuỗi) thì giờ đây với công cụ này ta không cần lặp nhiều như thê nữa

Với suy nghĩ trên DHN46 có 1 câu hỏi kính mong các anh chị trợ giúp

Cho 1 chuỗi dạng: s = "12;34;12;A;23;B;B;12;45;AB;12"
Bằng Vbscript.RegExp hãy tách ra các phần tử trùng trong dãy

Xin cảm ơn!
 
Upvote 0
Vbscript.RegExp quả là hay, với những bài toán tưởng chừng phải dùng vòng lặp duyệt toàn bộ mảng(chuỗi) thì giờ đây với công cụ này ta không cần lặp nhiều như thê nữa

Với suy nghĩ trên DHN46 có 1 câu hỏi kính mong các anh chị trợ giúp

Cho 1 chuỗi dạng: s = "12;34;12;A;23;B;B;12;45;AB;12"
Bằng Vbscript.RegExp hãy tách ra các phần tử trùng trong dãy

Xin cảm ơn!

Tóm lại kết quả cuối cùng sẽ là cái gì?
 
Upvote 0
Kết quả mong muốn của em là mảng gồm các phần tử trùng lặp: 12,B

Bạn thử xem
[gpecode=vb]Function Test(Str As String, C As String) As String
Str = C & Replace(Str, C, C & C) & C
With CreateObject("VBScript.RegExp")
.Pattern = "(" & C & "[^" & C & "]+" & C & ").*\1"
Do While .Test(Str)
Test = Test & .Execute(Str)(0).SubMatches(0)
Str = Replace(Str, .Execute(Str)(0).SubMatches(0), "")
Loop
End With
Test = Replace(Mid(Test, 2, Len(Test) - 2), C & C, C)
End Function [/gpecode]
 
Upvote 0
hoặc

[GPECODE=vb]
Function tenlot1(cell As Range) As String
On Error Resume Next
With CreateObject("vbscript.regexp")
.Pattern = "\s.+\s"
tenlot1 = Trim(.Execute(Trim(cell)).Item(0).Value)
End With
End Function
[/GPECODE]

------------------
Ái chà.
Dạng 2 viết xong gửi lên mới thấy là giống cách của dhn46.
Coi như không tính cách 2.

Nhân tiện rảnh rỗi thử làm phức tạp vấn đề, làm rắc rối cách 2 xem sao

[GPECODE=vb]
Function tenlot(cell As Range) As String
On Error Resume Next
With CreateObject("vbscript.regexp")
.Pattern = "\s.+(?=\s)"
tenlot = Trim(.Execute(Trim(cell)).Item(0).Value)
End With
End Function
[/GPECODE]
------------------

Nếu là một hàm cho cả họ, tên, tên lót thì góp vui một code

[GPECODE=vb]
Function tachhoten(cell As Range, Optional ByVal index As Long = 3) As String
With CreateObject("vbscript.regexp")
.Pattern = "(\S+)(.*)(\s\S+)"
tachhoten = Trim(.Replace(Trim(cell), "$" & index))
End With
End Function
[/GPECODE]
 
Upvote 0
Sáng nay gởi bài lên GPE để hỏi mà đến giờ mới vào để xem đáp án.

Vô cùng cảm kích các anh chị đã post lời giải.

Qua bài này chúng ta (những bạn còn yếu về VBA như mình) chắn chắn đã học rất nhiều cái hay khi cần thiết lập 1 Pattern phù hợp với nhu cầu.
 
Upvote 0
Nếu là một hàm cho cả họ, tên, tên lót thì góp vui một code

[GPECODE=vb]
Function tachhoten(cell As Range, Optional ByVal index As Long = 3) As String
With CreateObject("vbscript.regexp")
.Pattern = "(\S+)(.*)(\s\S+)"
tachhoten = Trim(.Replace(Trim(cell), "$" & index))
End With
End Function
[/GPECODE]

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
 
Upvote 0
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

File đính kèm

Upvote 0
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 !

Về ký tự "^" thì nó không đại diện cho bất cứ ký tự nào trong chuỗi cả. Ký tự đó chỉ có nghĩa là "vị trí ở đầu chuỗi". Vd. ta có Pattern = "^abc" thì có nghĩa là tìm tất cả các đoạn khớp với mẫu "^abc", tức các đoạn mà bắt đầu bằng vị trí đầu chuỗi và tiếp theo là 3 ký tự "abc". Nói nôm na là tìm các đoạn "abc" mà ở đầu chuỗi (trước "a" là "vị trí đầu chuỗi"). Tất nhiên "vị trí đầu chuỗi" chỉ có 1 nên nếu chuỗi cho trước có đoạn khớp với mẫu thì cũng chỉ có 1 đoạn khớp.
Tượng tự ký tự "$" trong Pattern xác định "vị trí cuối chuỗi" chứ không đại diện cho bất cứ ký tự nào trong chuỗi.Ví dụ có chuỗi s = "abcde xyz" và Pattern = "^abc" => tìm thấy 1 đoạn khớp "abc". Nếu Pattern = "yz$" => tìm thấy 1 đoạn khớp "yz".
Chú ý:
1. Ký tự "^" trong cấu trúc [^...] có ý nghĩa khác.
[abcxyz] có nghĩa là 1 ký tự trong tập {a, b, c, x, y, z}
[^abcxyz] có nghĩa là 1 ký tự KHÔNG thuộc tập {a, b, c, x, y, z}
2. Mặc định thì MultiLine = FALSE. Nếu MultiLine = TRUE thì "^" cũng có nghĩa là "vị trí đầu dòng" và "$" có nghĩa là "vị trí cuối dòng"

Trở về Pattern của tôi thì cần hiểu thêm ký tự "." (dấu chấm). Ký tự "." trong pattern có nghĩa là một ký tự bất kỳ khác ký tự \n (xuống dòng, dòng mới). Ký tự sao "*" có nghĩa là ký tự hoặc biểu thức trước nó xuất hiện 0 hoặc > 0 lần
Vậy
Mã:
                .MultiLine = True
                .Pattern = "^.*$"

Có nghĩa là: "tìm tất cả cả các đoạn mà mỗi đoạn là chuỗi (có độ lớn >= 0) các ký tự bất kỳ khác ký tự xuống dòng, bắt đầu từ vị trí đầu dòng và kết thúc bằng vị trí cuối dòng". Dịch ra ngôn ngữ dễ hiểu thì là: Tìm tất cả các dòng (kể cả dòng trống, tức có độ lớn = 0 - ký tự "." xuất hiện 0 lần) có trong chuỗi.
---------------
Bảng các ký tự

Ký tự|Ý nghĩa
Ký tự|Mối ký tự, trừ các ký tự đặc biệt [\^$.|?*+(), có nghĩa là chính mình, vd. g là g Ký tự { và } là chính mình nếu chúng không phải là một phần của biểu thức, vd. Như trong \d{3}
.|Dấu chấm đại diện cho 1 ký tự bất kỳ trừ ký tự \n
\|Các ký tự [\^$.|?*+(){} sau ký tự \ có nghĩa là chính mình, vd. \. có nghĩa là dấu chấm chứ không phải ký tự bất kỳ. \\ có nghĩa là \, còn \( có nghĩa là (
\Q...\E|chuỗi ký tự giữa \Q và \E (kể cả các ký tự đặc biệt) có nghĩa là chính mình? Vd. \Q+-*/\E khớp với +-*/
^|Đầu chuỗi
$|Cuối chuỗi
*|Ký tự sao * có nghĩa là ký tự hoặc biểu thức trước nó xuất hiện 0 hoặc > 0 lần, vd. “zo*” có nghĩa là “z” hoặc “zo...o”
+|Ký tự + có nghĩa là ký tự hoặc biểu thức trước nó xuất hiện ít nhất 1 lần. vd. “zo+” có thể là “zo” hoặc “zo...o” nhưng không là “z”
?|Dấu hỏi ? có nghĩa là ký tự hoặc biểu thức trước nó xuất hiện 0 hoặc 1 lần
{n,}|Có nghĩa là biểu thức được lặp lại ít nhất là n lần. vd.: "o{2,}" không có nghĩa "o" trong "Bob" nhưng có nghĩa là tất cả các ký tự "o" trong "foooood." o{1,} tương đương với "o+" còn "o{0,}" tương đương với "o*".
{n,m}
n >= 0,
m >= n|Có nghĩa là biểu thức phải được lặp lại ít nhất n lần nhưng không quá m lần. Vd. "o{1,3}" có nghĩa là "ooo" trong "fooooood" còn "o{0,1}" tương đương với "o?".
*?|Ký tự sao * có nghĩa là ký tự hoặc biểu thức trước nó xuất hiện 0 hoặc > 0 lần, vd. “zo*” có nghĩa là “z” hoặc “zo...o”
"+?"|Ký tự + có nghĩa là ký tự hoặc biểu thức trước nó xuất hiện ít nhất 1 lần. vd. “zo+” có thể là “zo” hoặc “zo...o” nhưng không là “z”
??|Dấu hỏi ? có nghĩa là ký tự hoặc biểu thức trước nó xuất hiện 0 hoặc 1 lần
{n,}?|Có nghĩa là biểu thức được lặp lại ít nhất là n lần. vd.: "o{2,}" không có nghĩa "o" trong "Bob" nhưng có nghĩa là tất cả các ký tự "o" trong "foooood." o{1,} tương đương với "o+" còn "o{0,}" tương đương với "o*".
{n,m}?
n >= 0,
m >= n|Có nghĩa là biểu thức phải được lặp lại ít nhất n lần nhưng không quá m lần. Vd. "o{1,3}" có nghĩa là "ooo" trong "fooooood" còn "o{0,1}" tương đương với "o?".
x|y|Dấu gạch đứng | là toán tử OR, vd. Nếu ta viết a|b|c thì có nghĩa là trong biểu thức xuất hiện a hoặc b hoặc c. Có thể dùng ngoặc để nhóm, vd. abc(def|xyz) khớp với abcdef hoặc abcxyz
{n}|Số n xác định ký tự hoặc biểu thức trước nó được lặp lại bao nhiêu lần Vd. “o{2}” có nghĩa là “oo”
[xyz]
[a-z]|Tập ký tự trong ngoặc vuông [] có nghĩa là 1 ký tự bất kỳ trong tập đó, vd. [abc] có nghĩa là a, b hoặc c cũng có thể dùng khoảng: [a-c]. Nếu muốn dùng các ký tự ^-]\ trong tập thì phải thêm vào đằng trước ký tự "\", vd. [\^\]] có nghĩa là "^" hoặc "]"
[^xyz]
[^m-z]|Ký tự ^ ở đầu tập có nghĩa là mọi ký tự trừ ký tự trong tập. Cũng có thể dùng khoảng.
\b|xác định vị trí nằm giữa từ (tức chuỗi các ký tự thuộc [a-zA-Z0-9_]) và ký tự [^A-Za-z0-9_]. Cũng có nghĩa là vị trí ^ hoặc $ nếu ký tự đầu tiên hoặc cuối cùng trong chuỗi thuộc [A-Za-z0-9_] Vd. "er\b" khớp với "er" trong "never" nhưng không khớp với "er" trong "verb". "\b" ở trong […] có nghĩa là ký tự backspace - "\x08". "[\b]" khớp với "\x08"
\B|xác định vị trí giữa 2 ký tự liên tiếp cùng thuộc [A-Za-z0-9_] hoặc cùng thuộc [^A-Za-z0-9_], vd. "ea*r\B" khớp với "ear" trong "never early".
\d|Có nghĩa là chữ số, tương đương với [0-9]. Được phép dùng trong […]
\D|Có nghĩa là không là chữ số, tương đương với [^0-9]
\a và \e|khớp với ký tự bell (\x07) và escape (\x1B). Được phép dùng trong […]
\f|ký tự điều khiển nhả trang - form feed. Được phép dùng trong […]
\n|Có nghĩa là ký tự dòng mới. Được phép dùng trong […]
\r|Có nghĩa là ký tự về đầu dòng. Được phép dùng trong […]
\s|Có nghĩa là tất cả các dấu cách trắng, tức dấu cách, TAB, form-feed, .... Tương đương với "[ \f\n\r\t\v]". Được phép dùng trong […]
\S|Có nghĩa là tất cả các ký tự trừ các dấu cách trắng. Tương đương với "[^ \f\n\r\t\v]"
\t|Có nghĩa là ký tự TAB. Được phép dùng trong […]
\v|ký tự điều khiển vertical tab. Được phép dùng trong […]
\w|Tương đương với "[A-Za-z0-9_]". Được phép dùng trong […]
\W|Tương đương với "[^A-Za-z0-9_]".
()\num|Matches num, where num is a positive integer. A reference back to remembered matches. For example, "(.)\1" matches two consecutive identical characters.
\n|Matches n, where n is an octal escape value. Octal escape values must be 1, 2, or 3 digits long. For example, "\11" and "\011" both match a tab character. "\0011" is the equivalent of "\001" & "1" Octal escape values must not exceed 256. If they do, only the first two digits comprise the expression. Allows ASCII codes to be used in regular expressions.
\xFF với FF là 2 ký tự hệ 16|khớp với ký tự có điểm mã là FF. vd. "\x41" khớp với ký tự "A", "\x041" khớp với "\x04" & "1". Được phép dùng trong […]

Thiết lập mặc định là "tham lam" (Greedy), tức tìm những đoạn dài nhất có thể mà khớp với mẫu. Nếu ta muốn tìm những đoạn ngắn nhất có thể mà khớp với mẫu thì thay vì *, +, ?, {n,}, {n,m} ta dùng phiên bản "lười biếng" (Lazy) của chúng: *?, +?, ??, {n,}?, {n,m}?
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Để tách tên mình dùng Pattern này
PHP:
Function ten(cell As Range)
   With CreateObject("vbscript.regexp")
      .Global = True
      .Pattern = ".*\s"
      ten = .Replace(Trim(cell), "")
   End With
End Function
Để tách lấy họ mình dùng Pattern này
PHP:
Function ho(cell As Range)
   With CreateObject("vbscript.regexp")
      .Global = True
      .Pattern = "\s.*"
      ho = .Replace(Trim(cell), "")
   End With
End Function
Xin hỏi các anh chị ngoài cách dưới đây có cách nào dùng 1 Pattern để lấy được các ký tự bên trong của dấu cách đầu và dấu cách cuối để tách phần tên lót ra hay không?
PHP:
Function tenlot(cell As Range)
Dim ho As String, ten As String
   With CreateObject("vbscript.regexp")
      .Global = True
      .Pattern = ".*\s"
      ten = .Replace(Trim(cell), "")
      .Pattern = "\s.*"
      ho = .Replace(Trim(cell), "")
      tenlot = Application.Trim(Replace(Replace(cell, ho, ""), ten, ""))
   End With
End Function
mới thấy trên diễn đàn cắt lấy tên bằng tìm kiếm và thay thế "* " thấy áp dụng được các trường hợp mình test "mình có thể sử lý các trắng thừa trước" sau đó áp dụng vào cái này thấy rất ok, mong các thành viên xem xét xem có trường hợp nào bị lỗi không

hàm cắt tên
Mã:
Sub VBSCRIPT()
Dim luat As Object
    Set luat = CreateObject("vbscript.regexp")
    luat.Global = True
    luat.Pattern = ".* "
    For i = 1 To 20
          Cells(i, 2) = luat.Replace(Cells(i, 1), "")
    Next
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
mới thấy trên diễn đàn cắt lấy tên bằng tìm kiếm và thay thế "* " thấy áp dụng được các trường hợp mình test "mình có thể sử lý các trắng thừa trước" sau đó áp dụng vào cái này thấy rất ok, mong các thành viên xem xét xem có trường hợp nào bị lỗi không

hàm cắt tên
Mã:
Sub VBSCRIPT()
Dim luat As Object
    Set luat = CreateObject("vbscript.regexp")
    luat.Global = True
    For i = 1 To 20
         luat.Pattern = ".* "
         Cells(i, 2) = luat.Replace(Cells(i, 1), "")
    Next
End Sub

Bạn không cho biết mục đich của hàm. Lấy gì mà xét xem nó đúng hay sai? Cắt tên nghĩa là gì? Cắt tên bỏ đi giữ lại họ, hay là cắt tên giữ lại và bọ họ đi?

Đúng hay sai chưa biết. Nhưng code dở ở hai điểm:

1. Cái Pattern không hề thay đổi. Để nó trong vòng lặp để chép đi chép lại 20 lần à?

2. Khi cần tách lấy một cụm ký tự thì dùng phương thức Match rồi lấy ra. Dùng phương thức Replace để xoá phần thừa là cách làm ngược.
 
Upvote 0
mới thấy trên diễn đàn cắt lấy tên bằng tìm kiếm và thay thế "* " thấy áp dụng được các trường hợp mình test "mình có thể sử lý các trắng thừa trước" sau đó áp dụng vào cái này thấy rất ok, mong các thành viên xem xét xem có trường hợp nào bị lỗi không

hàm cắt tên
Mã:
Sub VBSCRIPT()
Dim luat As Object
    Set luat = CreateObject("vbscript.regexp")
    luat.Global = True
    luat.Pattern = ".* "
    For i = 1 To 20
          Cells(i, 2) = luat.Replace(Cells(i, 1), "")
    Next
End Sub
Muốn tách lấy phần tên thì hãy tham khảo cách này của mình.
Cũng hơi nhức đầu tí nhưng nhìn thấy chuyên nghiệp lắm.
PHP:
Function TachTen(Str As String) As String
   With CreateObject("vbscript.regexp")
       .Global = True
       .Pattern = "(\S+$)"
       TachTen = Trim(.Execute(Trim(Str))(0).Submatches(0))
   End With
End Function
 
Upvote 0
Muốn tách lấy phần tên thì hãy tham khảo cách này của mình.
Cũng hơi nhức đầu tí nhưng nhìn thấy chuyên nghiệp lắm.
PHP:
Function TachTen(Str As String) As String
   With CreateObject("vbscript.regexp")
       .Global = True
       .Pattern = "(\S+$)"
       TachTen = Trim(.Execute(Trim(Str))(0).Submatches(0))
   End With
End Function
Lâu lắm mới thấy anh!
A bổ sung thêm code tách họ, tách đệm cho mng nghiên cứu đi anh.
 
Upvote 0
Lâu lắm mới thấy anh!
A bổ sung thêm code tách họ, tách đệm cho mng nghiên cứu đi anh.
Mấy đồ quỷ này giờ xưa lắm rồi nên ít thấy ai quan tâm. Hứa với nhau là đừng kêu giải thích mấy cái mì tôm cua của pattern nhé.

PHP:
Function TachTen(Str$, Optional Op As Long = 3)
With CreateObject("vbscript.regexp")
    .Global = True
    .Pattern = "(\S+)( .+ | )(\S+$)"
    TachTen = Trim(.Execute(Trim(Str))(0).Submatches(Op - 1))
End With
End Function
 
Upvote 0
Thuật toán của anh Hải có một vài chỗ chưa đúng. Do sử dụng phương thức Replace nên nếu rơi vào một trong các trường hợp sau đây kết quả sẽ không đúng:
1. Họ là chuỗi con của Tên ( Thị n)
2. Họ là chuỗi con của tên lót (Hồ Thị Hồng Hà)
3. Tên là chuỗi con của tên lót (Nguyễn Thị Thanh Thanh)

Tôi cũng viết thử một hàm 3 trong 1. Có thể tách họ, tên lót, tên.
[gpecode=vb]Function TachTen(Str As String, Optional Op As Long = 3)
With CreateObject("vbscript.regexp")
.Global = True
.Pattern = "(\S+)( .+ | )(\S+$)"
TachTen = Trim(.Execute(Trim(Str))(0).SubMatches(Op - 1))
End With
End Function[/gpecode]
Em cũng đang dùng hàm trên để xếp ABC cho danh sách học sinh:
Code VBA em đang dùng:
Sub XeptenABC()
Application.ScreenUpdating = False
Dim n As Long
n = Sheet2.[c65000].End(3).Row
Range("do7:do" & n).FormulaR1C1 = "=MahoaUNI(TachTen(RC3,3))"
Range("dp7:dp" & n).FormulaR1C1 = "=MahoaUNI(TachTen(RC3,2))"
Range("dq7:dq" & n).FormulaR1C1 = "=MahoaUNI(tachten(RC3,1))"
Range("B7:dq" & n).Sort Key1:=[do7], Order1:=1, Key2:=[dp7], Order2:=1, Key3:=[dq7], Order3:=1, Header:=xlNo
Range("do7:dq" & n).Clear

Application.ScreenUpdating = True
MsgBox "Da xep xong!"
End Sub

Function TachTen(str As String, Optional Op As Long = 3)
With CreateObject("vbscript.regexp")
.Global = True
.Pattern = "(\S+)( .+ | )(\S+$)"
TachTen = Trim(.Execute(Trim(str))(0).SubMatches(Op - 1))
End With
End Function

Public Function MahoaUNI(S) As String
Dim x, Sb, k, mu, skdau, sdau, Bdau, Bkdau As String
Dim i, m, n, dau, idau, ikdau As Integer

If IsNull(S) Then
Exit Function
ElseIf IsNumeric(S) Then
Sb = S
Else
S = Trim(S)
S = LCase(S) & ChrW(32)

skdau = ChrW(259) & ChrW(234) & ChrW(244) & ChrW(432) & ChrW(273) & ChrW(226) & ChrW(417)
Bkdau = "aeoudao"

sdau = ChrW(225) & ChrW(224) & ChrW(7843) & ChrW(227) & ChrW(7841) _
& ChrW(233) & ChrW(232) & ChrW(7867) & ChrW(7869) & ChrW(7865) _
& ChrW(237) & ChrW(236) & ChrW(7881) & ChrW(297) & ChrW(7883) _
& ChrW(243) & ChrW(242) & ChrW(7887) & ChrW(245) & ChrW(7885) _
& ChrW(250) & ChrW(249) & ChrW(7911) & ChrW(361) & ChrW(7909) _
& ChrW(253) & ChrW(7923) & ChrW(7927) & ChrW(7929) & ChrW(7925) _
& ChrW(7855) & ChrW(7857) & ChrW(7859) & ChrW(7861) & ChrW(7863) _
& ChrW(7889) & ChrW(7891) & ChrW(7893) & ChrW(7895) & ChrW(7897) _
& ChrW(7871) & ChrW(7873) & ChrW(7875) & ChrW(7877) & ChrW(7879) _
& ChrW(7913) & ChrW(7915) & ChrW(7917) & ChrW(7919) & ChrW(7921) _
& ChrW(7845) & ChrW(7847) & ChrW(7849) & ChrW(7851) & ChrW(7853) _
& ChrW(7899) & ChrW(7901) & ChrW(7903) & ChrW(7905) & ChrW(7907)
Bdau = "aaaaaeeeeeiiiiiooooouuuuuyyyyyaaaaaoooooeeeeeuuuuuaaaaaooooo"

For m = 1 To Len(S)
k = Mid(S, m, 1)
idau = InStr(1, sdau, k, 0)
ikdau = InStr(1, skdau, k, 0)
If idau > 0 Then
k = Mid(Bdau, idau, 1)
dau = idau Mod 5

If dau = 0 Then
dau = 5
End If


If idau > 0 And idau < 31 Then
mu = ""
ElseIf idau > 30 And idau < 51 Then
mu = "z"
Else
mu = "zw"
End If

k = k & mu

ElseIf ikdau > 0 Then
k = Mid(Bkdau, ikdau, 1)
If ikdau < 6 Then
k = k & "z"
Else
k = k & "zw"
End If
ElseIf k = ChrW(32) Then
k = dau & ChrW(32)
dau = ""
End If

x = x & k
Next
Sb = Sb & x
End If
MahoaUNI = Sb
End Function

Tuy nhiên DSHS xếp chưa được như ý muốn
VD 2 học sinh sau khi xếp thì có thứ tự như sau:
1. Nguyễn Quỳnh Nhi
2. Nguyễn Thị Anh Nhi

Nhưng theo đúng DSHS của GVCN lớp lại xếp là:
1. Nguyễn Thị Anh Nhi
2. Nguyễn Quỳnh Nhi

(Chắc là lấy từng tên đệm gần tên chính trước, sau đó dịch dần về phía Họ, vì tên đệm của học sinh có thể 1 từ, 2 từ, ... )
Bây giờ em muốn xếp DSHS theo GVCN lớp xếp thì em cần sửa gì không?
Mong mọi người trên GPE giúp em với, xin cảm ơn mọi người....
 
Upvote 0
Đã lập 40 cái chủ đề, hơn 200 bài viết mà không biết trình bày sao cho hợp lý.

Nội quy diễn đàn nên bổ sung điều khoản trình bày bài viết... như bài trên khác gì mớ rau.

Nhũng não, não nề...

1536682226930.png
 
Upvote 0
Upvote 0
Thì cứ.. kệ người ta đi bạn!
Tất nhiên em kệ người ta rồi. Chỉ là suy nghĩ thoảng qua của em, góp ý kiến ý cò với diễn đàn.
Mà em ý kiến vậy chỉ tổ thêm người ghét mình.
Diễn đàn ít bài kiểu như thế hay nhiều bài như thế cũng không ảnh hưởng gì tới em, nhưng chắc chắn ảnh hưởng tới diễn đàn.
 
Upvote 0
Về ký tự "^" thì nó không đại diện cho bất cứ ký tự nào trong chuỗi cả. Ký tự đó chỉ có nghĩa là "vị trí ở đầu chuỗi". Vd. ta có Pattern = "^abc" thì có nghĩa là tìm tất cả các đoạn khớp với mẫu "^abc", tức các đoạn mà bắt đầu bằng vị trí đầu chuỗi và tiếp theo là 3 ký tự "abc". Nói nôm na là tìm các đoạn "abc" mà ở đầu chuỗi (trước "a" là "vị trí đầu chuỗi"). Tất nhiên "vị trí đầu chuỗi" chỉ có 1 nên nếu chuỗi cho trước có đoạn khớp với mẫu thì cũng chỉ có 1 đoạn khớp.
Tượng tự ký tự "$" trong Pattern xác định "vị trí cuối chuỗi" chứ không đại diện cho bất cứ ký tự nào trong chuỗi.Ví dụ có chuỗi s = "abcde xyz" và Pattern = "^abc" => tìm thấy 1 đoạn khớp "abc". Nếu Pattern = "yz$" => tìm thấy 1 đoạn khớp "yz".
Chú ý:
1. Ký tự "^" trong cấu trúc [^...] có ý nghĩa khác.
[abcxyz] có nghĩa là 1 ký tự trong tập {a, b, c, x, y, z}
[^abcxyz] có nghĩa là 1 ký tự KHÔNG thuộc tập {a, b, c, x, y, z}
2. Mặc định thì MultiLine = FALSE. Nếu MultiLine = TRUE thì "^" cũng có nghĩa là "vị trí đầu dòng" và "$" có nghĩa là "vị trí cuối dòng"

Trở về Pattern của tôi thì cần hiểu thêm ký tự "." (dấu chấm). Ký tự "." trong pattern có nghĩa là một ký tự bất kỳ khác ký tự \n (xuống dòng, dòng mới). Ký tự sao "*" có nghĩa là ký tự hoặc biểu thức trước nó xuất hiện 0 hoặc > 0 lần
Vậy
Mã:
                .MultiLine = True
                .Pattern = "^.*$"

Có nghĩa là: "tìm tất cả cả các đoạn mà mỗi đoạn là chuỗi (có độ lớn >= 0) các ký tự bất kỳ khác ký tự xuống dòng, bắt đầu từ vị trí đầu dòng và kết thúc bằng vị trí cuối dòng". Dịch ra ngôn ngữ dễ hiểu thì là: Tìm tất cả các dòng (kể cả dòng trống, tức có độ lớn = 0 - ký tự "." xuất hiện 0 lần) có trong chuỗi.
---------------
Bảng các ký tự

Ký tự|Ý nghĩa
Ký tự|Mối ký tự, trừ các ký tự đặc biệt [\^$.|?*+(), có nghĩa là chính mình, vd. g là g Ký tự { và } là chính mình nếu chúng không phải là một phần của biểu thức, vd. Như trong \d{3}
.|Dấu chấm đại diện cho 1 ký tự bất kỳ trừ ký tự \n
\|Các ký tự [\^$.|?*+(){} sau ký tự \ có nghĩa là chính mình, vd. \. có nghĩa là dấu chấm chứ không phải ký tự bất kỳ. \\ có nghĩa là \, còn \( có nghĩa là (
\Q...\E|chuỗi ký tự giữa \Q và \E (kể cả các ký tự đặc biệt) có nghĩa là chính mình? Vd. \Q+-*/\E khớp với +-*/
^|Đầu chuỗi
$|Cuối chuỗi
*|Ký tự sao * có nghĩa là ký tự hoặc biểu thức trước nó xuất hiện 0 hoặc > 0 lần, vd. “zo*” có nghĩa là “z” hoặc “zo...o”
+|Ký tự + có nghĩa là ký tự hoặc biểu thức trước nó xuất hiện ít nhất 1 lần. vd. “zo+” có thể là “zo” hoặc “zo...o” nhưng không là “z”
?|Dấu hỏi ? có nghĩa là ký tự hoặc biểu thức trước nó xuất hiện 0 hoặc 1 lần
{n,}|Có nghĩa là biểu thức được lặp lại ít nhất là n lần. vd.: "o{2,}" không có nghĩa "o" trong "Bob" nhưng có nghĩa là tất cả các ký tự "o" trong "foooood." o{1,} tương đương với "o+" còn "o{0,}" tương đương với "o*".
{n,m}
n >= 0,
m >= n|Có nghĩa là biểu thức phải được lặp lại ít nhất n lần nhưng không quá m lần. Vd. "o{1,3}" có nghĩa là "ooo" trong "fooooood" còn "o{0,1}" tương đương với "o?".
*?|Ký tự sao * có nghĩa là ký tự hoặc biểu thức trước nó xuất hiện 0 hoặc > 0 lần, vd. “zo*” có nghĩa là “z” hoặc “zo...o”
"+?"|Ký tự + có nghĩa là ký tự hoặc biểu thức trước nó xuất hiện ít nhất 1 lần. vd. “zo+” có thể là “zo” hoặc “zo...o” nhưng không là “z”
??|Dấu hỏi ? có nghĩa là ký tự hoặc biểu thức trước nó xuất hiện 0 hoặc 1 lần
{n,}?|Có nghĩa là biểu thức được lặp lại ít nhất là n lần. vd.: "o{2,}" không có nghĩa "o" trong "Bob" nhưng có nghĩa là tất cả các ký tự "o" trong "foooood." o{1,} tương đương với "o+" còn "o{0,}" tương đương với "o*".
{n,m}?
n >= 0,
m >= n|Có nghĩa là biểu thức phải được lặp lại ít nhất n lần nhưng không quá m lần. Vd. "o{1,3}" có nghĩa là "ooo" trong "fooooood" còn "o{0,1}" tương đương với "o?".
x|y|Dấu gạch đứng | là toán tử OR, vd. Nếu ta viết a|b|c thì có nghĩa là trong biểu thức xuất hiện a hoặc b hoặc c. Có thể dùng ngoặc để nhóm, vd. abc(def|xyz) khớp với abcdef hoặc abcxyz
{n}|Số n xác định ký tự hoặc biểu thức trước nó được lặp lại bao nhiêu lần Vd. “o{2}” có nghĩa là “oo”
[xyz]
[a-z]|Tập ký tự trong ngoặc vuông [] có nghĩa là 1 ký tự bất kỳ trong tập đó, vd. [abc] có nghĩa là a, b hoặc c cũng có thể dùng khoảng: [a-c]. Nếu muốn dùng các ký tự ^-]\ trong tập thì phải thêm vào đằng trước ký tự "\", vd. [\^\]] có nghĩa là "^" hoặc "]"
[^xyz]
[^m-z]|Ký tự ^ ở đầu tập có nghĩa là mọi ký tự trừ ký tự trong tập. Cũng có thể dùng khoảng.
\b|xác định vị trí nằm giữa từ (tức chuỗi các ký tự thuộc [a-zA-Z0-9_]) và ký tự [^A-Za-z0-9_]. Cũng có nghĩa là vị trí ^ hoặc $ nếu ký tự đầu tiên hoặc cuối cùng trong chuỗi thuộc [A-Za-z0-9_] Vd. "er\b" khớp với "er" trong "never" nhưng không khớp với "er" trong "verb". "\b" ở trong […] có nghĩa là ký tự backspace - "\x08". "[\b]" khớp với "\x08"
\B|xác định vị trí giữa 2 ký tự liên tiếp cùng thuộc [A-Za-z0-9_] hoặc cùng thuộc [^A-Za-z0-9_], vd. "ea*r\B" khớp với "ear" trong "never early".
\d|Có nghĩa là chữ số, tương đương với [0-9]. Được phép dùng trong […]
\D|Có nghĩa là không là chữ số, tương đương với [^0-9]
\a và \e|khớp với ký tự bell (\x07) và escape (\x1B). Được phép dùng trong […]
\f|ký tự điều khiển nhả trang - form feed. Được phép dùng trong […]
\n|Có nghĩa là ký tự dòng mới. Được phép dùng trong […]
\r|Có nghĩa là ký tự về đầu dòng. Được phép dùng trong […]
\s|Có nghĩa là tất cả các dấu cách trắng, tức dấu cách, TAB, form-feed, .... Tương đương với "[ \f\n\r\t\v]". Được phép dùng trong […]
\S|Có nghĩa là tất cả các ký tự trừ các dấu cách trắng. Tương đương với "[^ \f\n\r\t\v]"
\t|Có nghĩa là ký tự TAB. Được phép dùng trong […]
\v|ký tự điều khiển vertical tab. Được phép dùng trong […]
\w|Tương đương với "[A-Za-z0-9_]". Được phép dùng trong […]
\W|Tương đương với "[^A-Za-z0-9_]".
()\num|Matches num, where num is a positive integer. A reference back to remembered matches. For example, "(.)\1" matches two consecutive identical characters.
\n|Matches n, where n is an octal escape value. Octal escape values must be 1, 2, or 3 digits long. For example, "\11" and "\011" both match a tab character. "\0011" is the equivalent of "\001" & "1" Octal escape values must not exceed 256. If they do, only the first two digits comprise the expression. Allows ASCII codes to be used in regular expressions.
\xFF với FF là 2 ký tự hệ 16|khớp với ký tự có điểm mã là FF. vd. "\x41" khớp với ký tự "A", "\x041" khớp với "\x04" & "1". Được phép dùng trong […]

Thiết lập mặc định là "tham lam" (Greedy), tức tìm những đoạn dài nhất có thể mà khớp với mẫu. Nếu ta muốn tìm những đoạn ngắn nhất có thể mà khớp với mẫu thì thay vì *, +, ?, {n,}, {n,m} ta dùng phiên bản "lười biếng" (Lazy) của chúng: *?, +?, ??, {n,}?, {n,m}?
e đang nghiên cứu món Pattern này mà đọc đến bài của bác muốn tung não quá :))) nhưng thực sự nó rất chi tiết, rất cám ơn sự nhiệt tình của bác! ^^^^
 
Upvote 0
Lâu quá mình quên hết rồi, giờ mình muốn replace dãy 123(x)456(y)789(z) ... thành 123+456+789, trong đó x,y,z,.. là những con số có các chữ số, vậy Pattern là gì? Nhờ các bạn giúp!. Mình muốn vừa rep vừa tính biểu thức và tìm x,y,z luôn.
 
Lần chỉnh sửa cuối:
Upvote 0
Lâu quá mình quên hết rồi, giờ mình muốn replace dãy 123(x)456(y)789(z) ... thành 123+456+789, trong đó x,y,z,.. là những con số có các chữ số, vậy Pattern là gì? Nhờ các bạn giúp!. Mình muốn vừa rep vừa tính biểu thức và tìm x,y,z luôn.
Gợi nhớ để bạn tự làm:
Cách 1. Tạo pattern với các group và .Replace(Text, "$1+$2+$3")
Cách 2. Global =True pattern = "\(\w{1}\)" .Replace(Text, "+")
 
Upvote 0
Lâu quá mình quên hết rồi, giờ mình muốn replace dãy 123(x)456(y)789(z) ... thành 123+456+789, trong đó x,y,z,.. là những con số có các chữ số, vậy Pattern là gì? Nhờ các bạn giúp!. Mình muốn vừa rep vừa tính biểu thức và tìm x,y,z luôn.
Mã:
Sub abcd()
Dim Str, Cong, Xyz
Str = "123(x)456(y)789(z)"
With CreateObject("vbscript.regexp")
    .Global = True
    .Pattern = "(\d+)(\([^\)]+\))"
    Cong = Evaluate(.Replace(Str, "+" & "$1"))
    Xyz = .Replace(Str, "$2" & " ")
End With
[a1] = Cong
[a2] = Xyz
End Sub
 
Upvote 0
Cám ơn hai bạn HeSanbiCHAOQUAY, mình vừa được cần câu vừa được cá mang về, giờ chỉ còn học cách câu!:)
 
Upvote 1

Bài viết mới nhất

Back
Top Bottom