Nhờ chỉnh code loại trùng text dùng REGEXP

Liên hệ QC

eke_rula

Thành viên tích cực
Tham gia
12/11/16
Bài viết
1,076
Được thích
1,245
Em có đoạn code:
PHP:
Sub tachtrung2()
    Dim i As Long, j As Long, text As String, text2 As String, text3 As String
    text3 = "Dien;Dien;Dan;dien;giai;phap;dien;dan;phap;excel;Excel;phap;dan;2017;2017;dien;EXCEL;2017"
    text = Replace(";" & text3 & ";", ";", "   ")
    With CreateObject("vbscript.regexp")
        .Global = True
        .ignorecase = True
        .Pattern = "((\s\w+\s).+)\2"
        Do While .test(text)
            text = .Replace(text, "$1 ")
            i = 0
            For Each subl In .Execute(text)
                If InStr(text2, Trim(.Execute(text).Item(i).submatches(1))) = 0 Then
                    text2 = text2 & " | " & Trim(.Execute(text).Item(i).submatches(1))
                End If
                i = i + 1
            Next
        Loop
    End With
    MsgBox ("- " & Application.Trim(text) + ChrW(10) & "- " & text2)
End Sub
Kết quả của đoạn code trên tạo ra là chuỗi sau khi loại trùng hết (text) và liệt kê các chuỗi text bị trùng (text2)
- Sau khi chay code được text2, nhưng đoạn text2 lúc nào cũng có dấu "|" ở đầu và cuối, em có thể dùng Application.SUBSTITUTE để loại dấu "|" đầu và cuối, nhưng trong VBA có hàm replace , em đã thử replace(text,text2,"",,1) nhưng không được, cho em hỏi là em có thể dùng replace trong trường hợp này được không?
- Kết quả text2="| Dien | dan | 2017 | phap | Dan | excel" , bị trùng chữ "dan" và "Dan", em đã dùng Instr để xác định xem xuất hiện trong chuỗi không nhưng sao kết quả text2 vẫn có trùng, nhờ các anh/chị xem và chỉnh code dùm em.
Em cám ơn!!
 
Lần chỉnh sửa cuối:
VBScript không phải là cong cụ chuyên text.
Muốn chơi Regex thì tìm mấy cái diễn đàn về Perl. Tuy nhiên, nếu bạn vào đó thì sẽ thấy chính họ cũng nhìn nhận Regex không phải là công cụ tốt để làm vệc này.
 
Upvote 0
VBScript không phải là cong cụ chuyên text.
Muốn chơi Regex thì tìm mấy cái diễn đàn về Perl. Tuy nhiên, nếu bạn vào đó thì sẽ thấy chính họ cũng nhìn nhận Regex không phải là công cụ tốt để làm vệc này.
Em đang nghiên cứu về Regexp,nên thấy nó xử lý tốt về text, tách những cái mình muốn được trong chuỗi text phức tạp, miễn sao viết được cái pattern hợp lý thì vấn đề trở nên rất đơn giản. Anh có thể giới thiệu cho em vài cách xử lý text khác trong VBA được không ạ, em cám ơn anh!!!
 
Upvote 0
Em đang nghiên cứu về Regexp,nên thấy nó xử lý tốt về text, tách những cái mình muốn được trong chuỗi text phức tạp, miễn sao viết được cái pattern hợp lý thì vấn đề trở nên rất đơn giản. Anh có thể giới thiệu cho em vài cách xử lý text khác trong VBA được không ạ, em cám ơn anh!!!
Chà dạo này thấy Anh nghiên cứu nhiều hè. Chắc Anh tính làm lớn đây.
 
Upvote 0
Em đang nghiên cứu về Regexp,nên thấy nó xử lý tốt về text, tách những cái mình muốn được trong chuỗi text phức tạp, miễn sao viết được cái pattern hợp lý thì vấn đề trở nên rất đơn giản. Anh có thể giới thiệu cho em vài cách xử lý text khác trong VBA được không ạ, em cám ơn anh!!!

Cỗ máy Regex lấy từ VBScript. Vì là script cho nên MS chế nó theo mẫu của JavaScript. Có một số giới hạn. Điển hình là nó khong có tính năng "dòm ngược".
Nếu muốn vọc cái này thì chơi trong JavaScript đã hơn. Ngôn ngữ này cho phép nối kết quả (piping) cho nên mấy cái lệnh đi vòng giải quyết rất gọn.
 
Upvote 0
Em có đoạn code:
PHP:
Sub tachtrung2()
    Dim i As Long, j As Long, text As String, text2 As String, text3 As String
    text3 = "Dien;Dien;Dan;dien;giai;phap;dien;dan;phap;excel;Excel;phap;dan;2017;2017;dien;EXCEL;2017"
    text = Replace(";" & text3 & ";", ";", "   ")
    With CreateObject("vbscript.regexp")
        .Global = True
        .ignorecase = True
        .Pattern = "((\s\w+\s).+)\2"
        Do While .test(text)
            text = .Replace(text, "$1 ")
            i = 0
            For Each subl In .Execute(text)
                If InStr(text2, Trim(.Execute(text).Item(i).submatches(1))) = 0 Then
                    text2 = text2 & " | " & Trim(.Execute(text).Item(i).submatches(1))
                End If
                i = i + 1
            Next
        Loop
    End With
    MsgBox ("- " & Application.Trim(text) + ChrW(10) & "- " & text2)
End Sub
Kết quả của đoạn code trên tạo ra là chuỗi sau khi loại trùng hết (text) và liệt kê các chuỗi text bị trùng (text2)
- Sau khi chay code được text2, nhưng đoạn text2 lúc nào cũng có dấu "|" ở đầu và cuối, em có thể dùng Application.SUBSTITUTE để loại dấu "|" đầu và cuối, nhưng trong VBA có hàm replace , em đã thử replace(text,text2,"",,1) nhưng không được, cho em hỏi là em có thể dùng replace trong trường hợp này được không?
- Kết quả text2="| Dien | dan | 2017 | phap | Dan | excel" , bị trùng chữ "dan" và "Dan", em đã dùng Instr để xác định xem xuất hiện trong chuỗi không nhưng sao kết quả text2 vẫn có trùng, nhờ các anh/chị xem và chỉnh code dùm em.
Em cám ơn!!
Quan điểm của tôi: Nếu dùng RegExp mà bỏ được vòng lập (gọn hơn cách thông thường) thì tôi sẽ dùng. Bằng ngược lại, nó dài dòng hơn thì thôi.. nghỉ xài
Bài này cứ dùng InStr bình thường cho dễ hiểu
 
Upvote 0
Quan điểm của tôi: Nếu dùng RegExp mà bỏ được vòng lập (gọn hơn cách thông thường) thì tôi sẽ dùng. Bằng ngược lại, nó dài dòng hơn thì thôi.. nghỉ xài
Bài này cứ dùng InStr bình thường cho dễ hiểu

Bạn này muốn thử Regex chứ không hẳn là muốn giải đề bài.
Chỉ rất tiếc là cái đề tài bạn ấy chọn lại đúng cái chỗ nhược của Regex.
 
Upvote 0
Quan điểm của tôi: Nếu dùng RegExp mà bỏ được vòng lập (gọn hơn cách thông thường) thì tôi sẽ dùng. Bằng ngược lại, nó dài dòng hơn thì thôi.. nghỉ xài
Bài này cứ dùng InStr bình thường cho dễ hiểu
Em chỉ muốn nghiên cứu về Reg thôi anh ạ, làm mấy bài như tách số điện thoại, tách email , hay tách một đoạn nào đấy trong một chuỗi phức tạp thì phải công thức rất phức tạp hay phải dùng SUBSTITUTE rất nhiều lần, như anh nói bài này có nhiều cách , dùng split kết hợp với Dictionary, hay split và instr thì đơn giản hơn ạ, chứ tách chuỗi dạng phức tạp theo em nghĩ regexp sẽ lợi thế hơn, nếu nói không đúng mong anh bỏ qua!!!
 
Upvote 0
Em chỉ muốn nghiên cứu về Reg thôi anh ạ, làm mấy bài như tách số điện thoại, tách email , hay tách một đoạn nào đấy trong một chuỗi phức tạp thì phải công thức rất phức tạp hay phải dùng SUBSTITUTE rất nhiều lần, như anh nói bài này có nhiều cách , dùng split kết hợp với Dictionary, hay split và instr thì đơn giản hơn ạ, chứ tách chuỗi dạng phức tạp theo em nghĩ regexp sẽ lợi thế hơn, nếu nói không đúng mong anh bỏ qua!!!
Nếu tôi làm thì bài này tôi sẽ dùng 1 trong 2 cách:
- Split + Dictionary
- Split + InStr
tuy nhiên tôi thấy InStr đã quá đủ rồi
 
Upvote 0
Em chỉ muốn nghiên cứu về Reg thôi anh ạ, làm mấy bài như tách số điện thoại, tách email , hay tách một đoạn nào đấy trong một chuỗi phức tạp thì phải công thức rất phức tạp hay phải dùng SUBSTITUTE rất nhiều lần, như anh nói bài này có nhiều cách , dùng split kết hợp với Dictionary, hay split và instr thì đơn giản hơn ạ, chứ tách chuỗi dạng phức tạp theo em nghĩ regexp sẽ lợi thế hơn, nếu nói không đúng mong anh bỏ qua!!!

Nhận dạng chuoix đúng là sở trường của Regex. Cái tên của nó là vậy mà.

Tuy nhiên, từ "phức tạp" nó cũng có vấn đề chủ quan của nó. Trong đề bài này, cái token của bạn là một tử,, Và từ bất kể, tức là đại trà. Regex không có cái gì để ưu việt với các giải thuật duyệt chuỗi khác cả. Tất cả tính chất "so chuỗi", và "dòm trước ngó sau" của nó đều không sử dụng được hiệu quả.
 
Upvote 0
Em có đoạn code:
PHP:
Sub tachtrung2()
    Dim i As Long, j As Long, text As String, text2 As String, text3 As String
    text3 = "Dien;Dien;Dan;dien;giai;phap;dien;dan;phap;excel;Excel;phap;dan;2017;2017;dien;EXCEL;2017"
    text = Replace(";" & text3 & ";", ";", "   ")
    With CreateObject("vbscript.regexp")
        .Global = True
        .ignorecase = True
        .Pattern = "((\s\w+\s).+)\2"
        Do While .test(text)
            text = .Replace(text, "$1 ")
            i = 0
            For Each subl In .Execute(text)
                If InStr(text2, Trim(.Execute(text).Item(i).submatches(1))) = 0 Then
                    text2 = text2 & " | " & Trim(.Execute(text).Item(i).submatches(1))
                End If
                i = i + 1
            Next
        Loop
    End With
    MsgBox ("- " & Application.Trim(text) + ChrW(10) & "- " & text2)
End Sub
Kết quả của đoạn code trên tạo ra là chuỗi sau khi loại trùng hết (text) và liệt kê các chuỗi text bị trùng (text2)
- Sau khi chay code được text2, nhưng đoạn text2 lúc nào cũng có dấu "|" ở đầu và cuối, em có thể dùng Application.SUBSTITUTE để loại dấu "|" đầu và cuối, nhưng trong VBA có hàm replace , em đã thử replace(text,text2,"",,1) nhưng không được, cho em hỏi là em có thể dùng replace trong trường hợp này được không?
- Kết quả text2="| Dien | dan | 2017 | phap | Dan | excel" , bị trùng chữ "dan" và "Dan", em đã dùng Instr để xác định xem xuất hiện trong chuỗi không nhưng sao kết quả text2 vẫn có trùng, nhờ các anh/chị xem và chỉnh code dùm em.
Em cám ơn!!



Khi có yếu tố trùng lặp đầu tiên phải nghĩ ngay đến việc đưa dữ liệu vào mảng (ARR) và sử dụng "Dictionary"
Còn nếu bạn vẫn muốn sử dụng regular expression, (già rồi ngại xem và chỉnh sửa code của người khác ^^) bạn thử tham khảo cách tôi liệt kê "Text2" như sau:
Mã:
Sub a()
Dim i&, tmp, text2$
Dim str As String, oMatch As IMatchCollection2
    str = "Dien;Dien;Dan;dien;giai;phap;dien;dan;phap;excel;Excel;phap;dan;2017;2017;dien;EXCEL;2017"
    str = "#" & Replace(str, ";", "#") & "#" ' chẳng hiểu sao lại phải thay thế ; thành #; nếu đã thay sao không thay bằng Chr(0) ?????
    With New RegExp
        .Global = True
        .IgnoreCase = True
        .Pattern = "#(\w+)#.*\1+"
        Do While .Test(str)
            Set oMatch = .Execute(str)
            tmp = oMatch(i).SubMatches(0)
            text2 = text2 & tmp
            str = Replace(str, tmp, "", , , vbTextCompare)
        Loop
        MsgBox text2
    End With
End Sub
 
Upvote 0
Khi có yếu tố trùng lặp đầu tiên phải nghĩ ngay đến việc đưa dữ liệu vào mảng (ARR) và sử dụng "Dictionary"
Còn nếu bạn vẫn muốn sử dụng regular expression, (già rồi ngại xem và chỉnh sửa code của người khác ^^) bạn thử tham khảo cách tôi liệt kê "Text2" như sau:
Mã:
Sub a()
Dim i&, tmp, text2$
Dim str As String, oMatch As IMatchCollection2
    str = "Dien;Dien;Dan;dien;giai;phap;dien;dan;phap;excel;Excel;phap;dan;2017;2017;dien;EXCEL;2017"
    str = "#" & Replace(str, ";", "#") & "#" ' chẳng hiểu sao lại phải thay thế ; thành #; nếu đã thay sao không thay bằng Chr(0) ?????
    With New RegExp
        .Global = True
        .IgnoreCase = True
        .Pattern = "#(\w+)#.*\1+"
        Do While .Test(str)
            Set oMatch = .Execute(str)
            tmp = oMatch(i).SubMatches(0)
            text2 = text2 & tmp
            str = Replace(str, tmp, "", , , vbTextCompare)
        Loop
        MsgBox text2
    End With
End Sub
Em chạy nó báo lỗi chỗ này oMatch As IMatchCollection2 anh ạ.
chẳng hiểu sao lại phải thay thế ; thành #; nếu đã thay sao không thay bằng Chr(0) ?????: 2 cái pattern khác nhau anh ạ, nên em nó replace nó về " ", cái pattern của em là để chạy cả text và text2 (text là loại bỏ không trùng luôn), cái parttern của anh chỉ liệt kê text2 thôi.
Replace(str, tmp, "", , , vbTextCompare) anh có thể giải thích dùm em đoạn này được không ạ? Em cám ơn anh!!!
 
Lần chỉnh sửa cuối:
Upvote 0
Em chạy nó báo lỗi chỗ này oMatch As IMatchCollection2 anh ạ.
chẳng hiểu sao lại phải thay thế ; thành #; nếu đã thay sao không thay bằng Chr(0) ?????: 2 cái pattern khác nhau anh ạ, nên em nó replace nó về " ", cái pattern của em là để chạy cả text và text2 (text là loại bỏ không trùng luôn), cái parttern của anh chỉ liệt kê text2 thôi.
Replace(str, tmp, "", , , vbTextCompare) anh có thể giải thích dùm em đoạn này được không ạ? Em cám ơn anh!!!
báo lỗi vì bạn chưa khai báo regex theo kiểu "sớm" , ( vào tool --> reference --> tìm thến microsoft vbscritp regular,....)
Replace(str, tmp, "", , , vbTextCompare) = replace( chuỗi chứa chuỗi cần thay thế , chuỗi thay thế bằng chuỗi khác, chuỗi thay thế, không phân biệt chữ hoa chữ thường)
 
Upvote 0
báo lỗi vì bạn chưa khai báo regex theo kiểu "sớm" , ( vào tool --> reference --> tìm thến microsoft vbscritp regular,....)
Replace(str, tmp, "", , , vbTextCompare) = replace( chuỗi chứa chuỗi cần thay thế , chuỗi thay thế bằng chuỗi khác, chuỗi thay thế, không phân biệt chữ hoa chữ thường)
Dạ em chỉnh lại cái new regexp thanh vbscript.regexp nên chạy được rồi anh, hic, cái anh dùng là replace của VBA , nãy giờ em tưởng là của Regexp, nên thấy lạ, em cám ơn anh!!!
 
Upvote 0
Em có đoạn code:
PHP:
Sub tachtrung2()
    Dim i As Long, j As Long, text As String, text2 As String, text3 As String
    text3 = "Dien;Dien;Dan;dien;giai;phap;dien;dan;phap;excel;Excel;phap;dan;2017;2017;dien;EXCEL;2017"
    text = Replace(";" & text3 & ";", ";", "   ")
    With CreateObject("vbscript.regexp")
        .Global = True
        .ignorecase = True
        .Pattern = "((\s\w+\s).+)\2"
        Do While .test(text)
            text = .Replace(text, "$1 ")
            i = 0
            For Each subl In .Execute(text)
                If InStr(text2, Trim(.Execute(text).Item(i).submatches(1))) = 0 Then
                    text2 = text2 & " | " & Trim(.Execute(text).Item(i).submatches(1))
                End If
                i = i + 1
            Next
        Loop
    End With
    MsgBox ("- " & Application.Trim(text) + ChrW(10) & "- " & text2)
End Sub
Kết quả của đoạn code trên tạo ra là chuỗi sau khi loại trùng hết (text) và liệt kê các chuỗi text bị trùng (text2)
- Sau khi chay code được text2, nhưng đoạn text2 lúc nào cũng có dấu "|" ở đầu và cuối, em có thể dùng Application.SUBSTITUTE để loại dấu "|" đầu và cuối, nhưng trong VBA có hàm replace , em đã thử replace(text,text2,"",,1) nhưng không được, cho em hỏi là em có thể dùng replace trong trường hợp này được không?
- Kết quả text2="| Dien | dan | 2017 | phap | Dan | excel" , bị trùng chữ "dan" và "Dan", em đã dùng Instr để xác định xem xuất hiện trong chuỗi không nhưng sao kết quả text2 vẫn có trùng, nhờ các anh/chị xem và chỉnh code dùm em.
Em cám ơn!!
Đọc code không hiểu hết, có vài ý này:
- Cái "For Each subl In .Execute(text)", biến "subl" không thấy xuất hiện trong các câu lệnh sau
- Dan & dan trong chuỗi text2 dùng thử ucase() hoặc lcase() xem sao
 
Upvote 0
Khi có yếu tố trùng lặp đầu tiên phải nghĩ ngay đến việc đưa dữ liệu vào mảng (ARR) và sử dụng "Dictionary"
...

Bạn có thấy cái "\2" nằm ở cuối cái pattern của chủ thớt hôn?
Cái kỹ thuật back reference này là kỹ thuật cao cấp. Không phải của dân mới học.
 
Upvote 0
Đọc code không hiểu hết, có vài ý này:
- Cái "For Each subl In .Execute(text)", biến "subl" không thấy xuất hiện trong các câu lệnh sau
- Dan & dan trong chuỗi text2 dùng thử ucase() hoặc lcase() xem sao
Cái "subl" là đại diện cho mỗi item trong regexp, nó chính là .Execute(text).Item(i) đấy bạn, vì regexp tạo ra dạng mảng collection nên mình dùng for Each để lấy ra.
Instr không phân biệt chữ hoa chữ thường thì phải, vì mấy cái text kia đều có hoa thường hết, nhưng loại được. Có lẽ nên dùng replace sẽ hợp lý hơn!!!
 
Lần chỉnh sửa cuối:
Upvote 0
Bạn có thấy cái "\2" nằm ở cuối cái pattern của chủ thớt hôn?
Cái kỹ thuật back reference này là kỹ thuật cao cấp. Không phải của dân mới học.
Cái \2 là cái (\s\w+\s) được lưu trong submacthes, và được dùng để liệt kê cái text2. Bài này em giải từ bài của anh @dhn46 thấy có anh @huuthang_bd giải rồi nhưng chỉ liệt kê cái text2 , chứ chưa loại trùng cái text, nên em làm lại với cái pattern khác, em có đọc bài về regexp của anh @hungpecc1 và anh @quanghai1969, thấy có mấy bài rất hay về Backreference của anh @siwtom nên có thể hiểu được phần nào.
 
Lần chỉnh sửa cuối:
Upvote 0
Web KT
Back
Top Bottom