Tách chuỗi trong một chuỗi dài

Liên hệ QC

mmeohoang

Thành viên mới
Tham gia
28/6/09
Bài viết
4
Được thích
0
Làm ơn giup mình với. Làm sao từ một chuỗi dài có thể tách thành 2 chuỗi có màu đỏ
 

File đính kèm

  • Book1.xlsx
    10.8 KB · Đọc: 25
Làm ơn giup mình với. Làm sao từ một chuỗi dài có thể tách thành 2 chuỗi có màu đỏ
Bạn dùng code này:
Mã:
Function splstr(ByVal str As String, Optional n As Byte = 1)
Static reg As Object
If reg Is Nothing Then Set reg = CreateObject("vbscript.regexp")
reg.Global = True: reg.Pattern = "(P[A-Z]{3}\d{9})[^\d]*([\d,]+)"
If reg.test(str) Then
    If n = 1 Then
        splstr = reg.Execute(str)(0).submatches(0)
    Else
        splstr = CLng(reg.Execute(str)(0).submatches(1))
    End If
End If
End Function
Công thức tách mã hợp đồng, khách hàng=splstr($A3,1)
tách số tiền =splstr($A3,2)
 

File đính kèm

  • Book1 (33).xlsb
    18.7 KB · Đọc: 17
Bạn dùng code này:
Mã:
Function splstr(ByVal str As String, Optional n As Byte = 1)
Static reg As Object
If reg Is Nothing Then Set reg = CreateObject("vbscript.regexp")
reg.Global = True: reg.Pattern = "(P[A-Z]{3}\d{9})[^\d]*([\d,]+)"
If reg.test(str) Then
    If n = 1 Then
        splstr = reg.Execute(str)(0).submatches(0)
    Else
        splstr = CLng(reg.Execute(str)(0).submatches(1))
    End If
End If
End Function
Công thức tách mã hợp đồng, khách hàng=splstr($A3,1)
tách số tiền =splstr($A3,2)
Ký tự đầu <>"P" thì sao bạn :p
 
Làm ơn giup mình với. Làm sao từ một chuỗi dài có thể tách thành 2 chuỗi có màu đỏ
Nếu không dùng hàm thì thử chạy sub dưới xem sao
Mã:
Sub Tach()
Dim Nguon
Dim Kq
Dim i, j, t
Nguon = Sheet1.Range("a3", Sheet1.Range("a3").End(xlDown))
ReDim Kq(1 To UBound(Nguon), 1 To 2)
For i = 1 To UBound(Nguon)
    t = Replace(Nguon(i, 1), """" & "," & """", "|")
    t = Split(t, "|")
    Kq(i, 2) = t(4)
    For Each j In Split(t(2))
        If Len(j) = 13 Then
            Kq(i, 1) = j
            Exit For
        End If
    Next j
Next i
Sheet1.Range("b3").Resize(UBound(Kq), UBound(Kq, 2)).ClearContents
Sheet1.Range("b3").Resize(UBound(Kq), UBound(Kq, 2)) = Kq
End Sub
 
Nếu kí tự đầu bất kì, sửa chỗ P[A-Z]{3} thành [A-Z]{4} là được.
A-Za-z chứ

về bài #2, thông thường thì cách viết code là nếu hàm tính ra một mảng thì cứ cho nó trả về mảng đó. Và viết thêm hàm khác để gọi hàm này, lấy ra đúng phần tử. Như vậy, lúc cần, tôi có thể dùng hàm chính để lấy ra luôn cả mảng (chọn 2 ô, gõ công thức, và ctrl+shift+enter)
 
Bạn dùng code này:
Mã:
Function splstr(ByVal str As String, Optional n As Byte = 1)
Static reg As Object
If reg Is Nothing Then Set reg = CreateObject("vbscript.regexp")
reg.Global = True: reg.Pattern = "(P[A-Z]{3}\d{9})[^\d]*([\d,]+)"
If reg.test(str) Then
    If n = 1 Then
        splstr = reg.Execute(str)(0).submatches(0)
    Else
        splstr = CLng(reg.Execute(str)(0).submatches(1))
    End If
End If
End Function
Công thức tách mã hợp đồng, khách hàng=splstr($A3,1)
tách số tiền =splstr($A3,2)
Bạn có thể giải thích Pattern trên giúp. Mơ hồ về Regexp quá nên chưa hiểu hết được.

Mã:
[^\d]*([\d,]+)
 
A-Za-z chứ

về bài #2, thông thường thì cách viết code là nếu hàm tính ra một mảng thì cứ cho nó trả về mảng đó. Và viết thêm hàm khác để gọi hàm này, lấy ra đúng phần tử. Như vậy, lúc cần, tôi có thể dùng hàm chính để lấy ra luôn cả mảng (chọn 2 ô, gõ công thức, và ctrl+shift+enter)
Tôi nhớ các item hay các submatches trong item đâu có trả về mảng , muốn lấy thì phải gán trực tiếp vô lấy thôi, giả sử có trả về mảng thì cột số tiền sẽ trả về String sẽ tốn thêm bước nữa để trả về số, trong code tôi tách ra sử dụng CLng để chuyển về số.
 
Bạn có thể giải thích Pattern trên giúp. Mơ hồ về Regexp quá nên chưa hiểu hết được.

Mã:
[^\d]*([\d,]+)
Có vẻ như là: Theo thứ tự - Không lấy ký tự số từ 0 -> n lần , lấy các ký tự số và dấu phẩy từ 1 -> n lần
Sau đó dùng submatches lấy kết quả
 
Bạn có thể giải thích Pattern trên giúp. Mơ hồ về Regexp quá nên chưa hiểu hết được.

Mã:
[^\d]*([\d,]+)
Để giải thích hết cái pattern, giải thích ngang khó nói (P[A-Z]{3}\d{9})[^\d]*([\d,]+)
P[A-Z]{3}\d{9}) Tìm chuỗi bắt đầu bằng P có 3 kí tự tiếp thuộc tập [A-Z] 9 kí tự sau là số
[^\d]* chỗ này là các kí tự khác số (có thể không có), chỗ này dễ bị bẫy, có thể viết (P[A-Z]{3}\d{9}).*([\d,]+), nhưng theo mặc định lấy kết quả dài nhất của regexp kết quả trả về của ([\d,]+) sẽ không đúng nên phải sử dụng [^\d]* tức là không phải số, nếu đổi mặc định lấy chuỗi ngắn nhất thì pattern (P[A-Z]{3}\d{9}).*([\d,]+) này sẽ đúng
([\d,]+) chuỗi có số và dấu ,

Ví dụ chuỗi: PNYM000113516","","385,207" thì (P[A-Z]{3}\d{9}) là PNYM000113516, [^\d]* là ",""," và ([\d,]+) là 385,207
Bài đã được tự động gộp:
 
Không biết reg.Global = True để làm gì.

Mặc định là False. Khi tìm được 1 đoạn khớp thì reg dọn đồ. Khi True thì mặc dù đã tìm được thì reg vẫn cố tìm tiếp cho tới cuối chuỗi. Lãng phí không cần thiết. Chỉ nên đổi thành True khi muốn lấy tất cả (>1) các đoạn khớp.
 
Tôi nhớ các item hay các submatches trong item đâu có trả về mảng , muốn lấy thì phải gán trực tiếp vô lấy thôi, giả sử có trả về mảng thì cột số tiền sẽ trả về String sẽ tốn thêm bước nữa để trả về số, trong code tôi tách ra sử dụng CLng để chuyển về số.
Tôi chỉ nói về thủ thuật viết function. Bởi vì hầu hết người học code ở diễn đàn này theo gương của một bậc đàn anh đàn chị, chủ yếu chỉ thích viết một cục function/sub duy nhất và dùng tham số để điều khiển. Thói quen đó không hề sai, nhưng tới một trình độ nào đó sẽ thấy giới hạn của nó.
 
Không biết reg.Global = True để làm gì.

Mặc định là False. Khi tìm được 1 đoạn khớp thì reg dọn đồ. Khi True thì mặc dù đã tìm được thì reg vẫn cố tìm tiếp cho tới cuối chuỗi. Lãng phí không cần thiết. Chỉ nên đổi thành True khi muốn lấy tất cả (>1) các đoạn khớp.
Tôi copy code cũ chỉ sữa pattern nên không để ý, cấu trúc regexp thì cũng có nhiêu đó thôi.
 
Không hẳn vậy. Khi sử dụng Regex thì phải luôn nhớ rằng nó:
1. Nặng ký. Trừ phi có kỹ thuật cache dữ liệu để hiệu quả hoá. Kỹ thuật này hơi rắc rối.
2. Tham lam. Phải biết cách giới hạn độ tham lam của nó.
 
Không hẳn vậy. Khi sử dụng Regex thì phải luôn nhớ rằng nó:
1. Nặng ký. Trừ phi có kỹ thuật cache dữ liệu để hiệu quả hoá. Kỹ thuật này hơi rắc rối.
2. Tham lam. Phải biết cách giới hạn độ tham lam của nó.
À, ý tôi nói là các bài regexp phần lớn chỉ thay đổi pattern có thể copy lại và sửa pattern thôi, mấy tham số khác có thể thêm bớt cho phù hợp, tôi làm công thức hay code đều ít quan tâm đến tốc độ, trừ khi thực tế thấy nó chậm quá mới ngồi xem lại vì quan trọng đầu tiên là có kết quả trước đã. Cũng hiểu ít về sự nặng của regexp , nhưng thấy nó ra kết quả là mừng rồi đối với tôi regexp như kiểu đánh đố làm có cảm giác thú vị.
 
Ở bài #12 tôi có nói đến cụm từ "thói quen".
Hồi nhỏ chúng ta học làm toán nhân, đặt con số dài lên trên và con số ngắn ở dưới. Lúc đó đâu có ai được dạy là như vậy nhân nhanh hơn?
Thói quen từ từ nhập tâm thành phản xạ.
 
Không hẳn vậy. Khi sử dụng Regex thì phải luôn nhớ rằng nó:

2. Tham lam. Phải biết cách giới hạn độ tham lam của nó.
Theo tôi không cần. Tất nhiên để thay đổi mặc định "tham lam" thành "chừng mực" thì phải biết là phải thêm ?. Nhưng ý tôi là không phải cứ dùng *, +, ?, {n,}, {n,m} là phải thêm ? để thay đổi thành "chừng mực"

Chỉ có 2 trường hợp:

1. Nếu thay đổi mặc định thì kết quả khác nhau. Tức nếu để mặc định thì có kết quả a, nếu thay mặc định thì kết quả b, mà Len(a) > Len(b). Rõ ràng người dùng bắt buộc phải quyết định để mặc định hay thay đổi. Nếu anh ta có nhu cầu lấy đoạn khớp dài nhất có thể thì rõ rành anh ta phải để mặc định.. Ngược lại thì phải thay đổi mặc định.
Trong trường hợp này dù người dùng chọn gì thì đó là lựa chọn vì nhu cầu của anh ta chứ không là lựa chọn vì sự tối ưu của regex.

2. Nếu thay đổi mặc định thì kết quả như nhau. Tức nếu để mặc định thì có kết quả a, nếu thay mặc định thì kết quả cũng là a. Kết quả trong chủ đề này chính là loại này.
Chỉ có 2 trường hợp:
- Người dùng thay đổi mặc định. Khi tìm được đoạn a khớp với pattern thì regex kết thúc
- Người dùng không thay đổ mặc định. Lúc này sau khi tìm được a thì regex vẫn cố tiếp tục mở rộng thêm. Nhưng chỉ cần mở rộng thêm 1 ký tự thôi thì "a<1 ký tự>" sẽ không còn khớp với pattern nữa. Lúc này regex kết thúc.

Như vậy trong trường hợp này nếu người dùng không thay đổi mặc định thì chỉ tốn thêm 1 bước kiểm tra khi mở rộng thêm 1 ký tự (nên nhớ là khi cố mở rộng thêm mà regex thấy không khớp với pattern nữa thì nó ngừng chứ không phải mở rộng tiếp đến cuối chuỗi. Vì khi "a<1 ký tự>" không khớp thì "a<nhiều ký tự>" không bao giờ khớp). Cái mất mát này nó còn nhỏ hơn cả "chả là gì cả" nên chả ai viết pattern lại thay đổi mặc định chỉ để tiết kiệm nó.

Không phải cứ dùng *, +, ?, {n,}, {n,m} là phải thêm ? để thay đổi mặc định. Trên thực tế người ta chỉ thay đổi mặc định khi gặp trường hợp 1, và cũng chỉ khi người ta muốn lấy đoạn khớp ngắn nhất có thể. Nhưng đó là sự bắt buộc vì nhu cầu của người dùng chứ không phải vì sự tối ưu của regex.
 
Web KT
Back
Top Bottom