Xử lý Chuỗi, tách số ra khỏi chuỗi

Liên hệ QC

TuanPV2803

Thành viên mới
Tham gia
27/7/18
Bài viết
13
Được thích
2
Dear các anh chị!
Em có một bảng tính gồm rất nhiều mã hàng như sau:
CP950x2150mt
cox1230x900
Ctp560x1830tl
.....
Em muốn viết code tách riêng các chuỗi số ra 2 cột khác nhau ví dụ:


CP950x2150mt

950

2150

Nhưng thật sự em đã tìm kiếm rất nhiều và chỉ thấy tách ra thành 9502150
Vậy rất mong các anh chị em trong diễn đàn giúp đỡ em với!
Em xin chân thành cảm ơn!
Em gửi file đính kèm mong các anh chị em giúp em với ạ!
 

File đính kèm

Dear các anh chị!
Em có một bảng tính gồm rất nhiều mã hàng như sau:
CP950x2150mt
cox1230x900
Ctp560x1830tl
.....
Em muốn viết code tách riêng các chuỗi số ra 2 cột khác nhau ví dụ:

CP950x2150mt

950

2150

Nhưng thật sự em đã tìm kiếm rất nhiều và chỉ thấy tách ra thành 9502150
Vậy rất mong các anh chị em trong diễn đàn giúp đỡ em với!
Em xin chân thành cảm ơn!
Em gửi file đính kèm mong các anh chị em giúp em với ạ!
Góp vui thêm công thức:
Mã:
C11=LOOKUP(10^9,--MID(B11,LOOKUP(10^9,SEARCH(TEXT(ROW($1:$99),"0x0"),B11))-ROW($1:$9)+1,ROW($1:$9)))
D11=LOOKUP(10^9,--MID(B11,LOOKUP(10^9,SEARCH(TEXT(ROW($1:$99),"0x0"),B11))+2,ROW($1:$9)))
 
Upvote 0
Dear các anh chị!
Em có một bảng tính gồm rất nhiều mã hàng như sau:
CP950x2150mt
cox1230x900
Ctp560x1830tl
.....
Em muốn viết code tách riêng các chuỗi số ra 2 cột khác nhau ví dụ:

CP950x2150mt

950

2150

Nhưng thật sự em đã tìm kiếm rất nhiều và chỉ thấy tách ra thành 9502150
Vậy rất mong các anh chị em trong diễn đàn giúp đỡ em với!
Em xin chân thành cảm ơn!
Em gửi file đính kèm mong các anh chị em giúp em với ạ!
Góp thêm tí gió cho thuyền ra khơi.
Mã:
Option Explicit

Sub TachSo()
Dim SArr, Res
Dim i
SArr = Sheet1.Range("b11", Sheet1.Range("b65000").End(xlUp))
ReDim Res(1 To UBound(SArr), 1 To 2)
With CreateObject("VbScript.RegExp")
    .Global = True
    .IgnoreCase = True
    .Pattern = "\D+(\d+)[x](\d+).*"
    For i = 1 To UBound(SArr)
        If .test(SArr(i, 1)) Then
            Res(i, 1) = .Replace(SArr(i, 1), "$1")
            Res(i, 2) = .Replace(SArr(i, 1), "$2")
        End If
    Next i
End With
With Sheet1
.Range("c11", "d" & UBound(Res) + 10).ClearContents
.Range("c11", "d" & UBound(Res) + 10) = Res
End With
End Sub
 
Upvote 0
Góp thêm tí gió cho thuyền ra khơi.
Mã:
Option Explicit

Sub TachSo()
Dim SArr, Res
Dim i
SArr = Sheet1.Range("b11", Sheet1.Range("b65000").End(xlUp))
ReDim Res(1 To UBound(SArr), 1 To 2)
With CreateObject("VbScript.RegExp")
    .Global = True
    .IgnoreCase = True
    .Pattern = "\D+(\d+)[x](\d+).*"
    For i = 1 To UBound(SArr)
        If .test(SArr(i, 1)) Then
            Res(i, 1) = .Replace(SArr(i, 1), "$1")
            Res(i, 2) = .Replace(SArr(i, 1), "$2")
        End If
    Next i
End With
With Sheet1
.Range("c11", "d" & UBound(Res) + 10).ClearContents
.Range("c11", "d" & UBound(Res) + 10) = Res
End With
End Sub
Gió của bạn hơi nhiều quá. Có lẽ bạn quen theo các vị kỳ cựu ở diễn đàn này và thích dùng hàm Replace.
Nếu bạn dùng hàm Execute thì chỉ phải gọi 1 lần, và lấy mấy cái Submatches của nó.

[x] tức là x. Dấu ngoặc vuông dùng để làm một danh sách các ký tự cần match. Ở đây bạn chỉ có 1.
Đồng thời cũng nên lưu ý là cái mẫu của bạn thuộc dạng "tham lam", chạy tốn năng lượng.

Nên tập quen cách lấy submatches và diễn mẫu pattern.
 
Upvote 0
Kiểm thấy Code của Anh @HieuCD bị một lỗi, Nếu thừa ký tự phân biệt là "x"
Phương thức Split sẽ bị vô hiệu hóa tác dụng . Ví dụ chuỗi là "xxxx123x456xxxx"
Vì thế nếu chuỗi không theo nguyên tắc thì code vẫn sẽ gặp lỗi

Và thấy mọi người viết Hàm với VBA cũng vui vui vậy nên tham gia một Hàm

Diễn Giải:
Duyệt chuỗi "xxxx123x456xxxx"
Nếu tìm thấy "x" thì tìm ngược về trước để lấy số đứng trước
Nếu tồn tại số đứng trước thì Tiếp tục duyệt tìm số đứng sau
Nếu tìm thấy "x" mà không tìm được số đứng trước và số đứng sau thì tiếp tục tìm kiếm cho đến khi kết thúc

Sử dụng:
NumberBefore = ReNumber("xxxx123x456xxxx")
NumberAfter = ReNumber("xxxx123x456xxxx", 1)

Mọi người thử code dưới và thêm góp ý chỉnh sửa sai sót
PHP:
Function ReNumber&(str$, Optional idx& = 0)
  Dim i&, j&, k&, strB$, strA$, strMid$
  For i = 1 To Len(str)
    If strB <> "" Then
      strMid = Mid$(str, k + 1, i - k)
      If Not IsNumeric(strMid) Then Exit For
      strA = strMid
    End If
    If LCase$(Mid$(str, i, 1)) = "x" And LCase$(Mid$(str, i + 1, 1)) <> "x" Then
      k = i
      For j = 1 To k - 1
        strMid = Mid$(str, j, k - j)
        If IsNumeric(strMid) Then strB = strMid: Exit For
      Next j
    End If
  Next
  If strA <> "" Then ReNumber = IIf(idx = 0, strB, strA)
End Function
 
Lần chỉnh sửa cuối:
Upvote 0
Kiểm thấy Code của Anh @HieuCD bị một lỗi, Nếu thừa ký tự phân biệt là "x"
Phương thức Split sẽ bị vô hiệu hóa tác dụng . Ví dụ chuỗi là "xxxx123x456xxxx"
Vì thế nếu chuỗi không theo nguyên tắc thì code vẫn sẽ gặp lỗi

Và thấy mọi người viết Hàm với VBA cũng vui vui vậy nên tham gia một Hàm

Diễn Giải:
Duyệt chuỗi "xxxx123x456xxxx"
Nếu tìm thấy "x" thì tìm ngược về trước để lấy số đứng trước
Nếu tồn tại số đứng trước thì Tiếp tục duyệt tìm số đứng sau
Nếu tìm thấy "x" mà không tìm được số đứng trước và số đứng sau thì tiếp tục tìm kiếm cho đến khi kết thúc

Sử dụng:
NumberBefore = ReNumber("xxxx123x456xxxx")
NumberAfter = ReNumber("xxxx123x456xxxx", 1)

Mọi người thử code dưới và thêm góp ý chỉnh sửa sai sót
PHP:
Function ReNumber&(str$, Optional idx& = 0)
  Dim i&, j&, k&, strB$, strA$, strMid$
  For i = 1 To Len(str)
    If strB <> "" Then
      strMid = Mid$(str, k + 1, i - k)
      If Not IsNumeric(strMid) Then Exit For
      strA = strMid
    End If
    If LCase$(Mid(str, i, 1)) = "x" Then
      k = i
      For j = 1 To k - 1
        strMid = Mid$(str, j, k - j)
        If IsNumeric(strMid) Then strB = strMid: Exit For
      Next j
    End If
  Next
  If strB <> "" Then ReNumber = IIf(idx = 0, strB, strA)
End Function
Viết code nên căn cứ vào tình huống thực tế đưa ra giải pháp phù hợp, Không nên thay đổi đặc điểm của dữ liệu
Theo code trên, trong dữ liệu có trường hợp 3 nhóm số "xx1xxx234x456xxx" thì xử lý như thế nào? Nếu chỉ có 2 nhóm số cần chi tới 2 vòng lặp ?
 
Upvote 0
Giải thuật mò ký tự thì hiệu quả của nó dựa vào dạng phức tạp của chuỗi đầu vào.
Nếu chuỗi dài thòng lòng và số/kết quả thường nằm ở gần đầu thì duyệt từng ký tự - duyệt lấy được kết quả rồi thì ngưng.
Nếu chuỗi đơn giản (như đề bài) thì dùng hàm tìm ký tự (InStr) rồi lấy trái và phải - dùng hàm Split thì chỉ là một hình thức khác của phương pháp tìm ký tự. Nếu ký tự có thể xuất hiện nhiều lần thì giải thuật chỉ cần thêm phần xét số.

Viết code nên căn cứ vào tình huống thực tế đưa ra giải pháp phù hợp, Không nên thay đổi đặc điểm của dữ liệu
Theo code trên, trong dữ liệu có trường hợp 3 nhóm số "xx1xxx234x456xxx" thì xử lý như thế nào? Nếu chỉ có 2 nhóm số cần chi tới 2 vòng lặp ?
Bao nhiêu vòng lặp cũng không thành vấn đề. Bởi vì code ấy nó đã rắc rối từ căn bản. Và rắc rối mà chưa chắc đã đúng.
Nếu chuỗi là abc123xyz456abc thì nó vẫn lấy ra 123. Đơn giản vậy thôi.
 
Upvote 0
Viết code nên căn cứ vào tình huống thực tế đưa ra giải pháp phù hợp, Không nên thay đổi đặc điểm của dữ liệu
Theo code trên, trong dữ liệu có trường hợp 3 nhóm số "xx1xxx234x456xxx" thì xử lý như thế nào? Nếu chỉ có 2 nhóm số cần chi tới 2 vòng lặp ?
Ý trên của em đã nói rõ "Nếu thừa ký tự phân biệt là x - 'DP100x400xL', 'DP100x400Lx'"
Còn ví dụ chỉ là để Kiểm tra thử thôi.
Vấn đề vòng lặp cũng không ảnh hưởng lớn đến tốc độ với chuỗi dạng này.

Cảm ơn Anh đã góp ý , thêm một điều kiện ràng buộc nếu dữ liệu như Anh gợi ý:
PHP:
If LCase$(Mid(str, i, 1)) = "x" And LCase$(Mid(str, i + 1, 1)) <> "x" Then
Nếu chuỗi là abc123xyz456abc thì nó vẫn lấy ra 123
Lúc đầu em để code: StrA là chuỗi Số đứng trước, StrB là chuỗi số đứng sau.
Khi định nghĩa trong suy nghĩ hiểu StrB, StrA là String Before và String After
Nhìn lại code biết mình đã nhầm. Khi sửa ngược lại đã bị thiếu sót khâu trả kết quả
Mã:
StrB = "" đã sửa lại StrA = ""
 
Lần chỉnh sửa cuối:
Upvote 0
Em mới tập viết mãi mới được cái này. Mong mọi người chỉ bảo thêm ạ
Mã:
Function ExtractNumber(ByVal txt As String, ByVal N As Long) As Long
    Dim I As Long, strTemp As String
For I = 1 To Len(txt)
    Select Case Asc(Mid(txt, I, 1))
        Case 40 To 57, 94
            strTemp = strTemp & Mid(txt, I, 1)
        Case Else
            strTemp = strTemp & " "
    End Select
Next I
If Len(strTemp) Then strTemp = Application.Trim(strTemp)
If Len(strTemp) Then ExtractNumber = Split(strTemp, " ")(N - 1)
End Function
 

File đính kèm

Upvote 0
Em mới tập viết mãi mới được cái này. Mong mọi người chỉ bảo thêm ạ
Mã:
Function ExtractNumber(ByVal txt As String, ByVal N As Long) As Long
    Dim I As Long, strTemp As String
For I = 1 To Len(txt)
    Select Case Asc(Mid(txt, I, 1))
        Case 40 To 57, 94
            strTemp = strTemp & Mid(txt, I, 1)
        Case Else
            strTemp = strTemp & " "
    End Select
Next I
If Len(strTemp) Then strTemp = Application.Trim(strTemp)
If Len(strTemp) Then ExtractNumber = Split(strTemp, " ")(N - 1)
End Function
Không cần phải duyệt hết chuỗi. Sử dụng 1 biến đếm để đếm số chuỗi số liên tục và chỉ duyệt đến hết chuỗi số cần lấy.
 
Upvote 0
Không cần phải duyệt hết chuỗi. Sử dụng 1 biến đếm để đếm số chuỗi số liên tục và chỉ duyệt đến hết chuỗi số cần lấy.
Dạ. Cám ơn Anh rất nhiều. Em sửa lại như thế này có được không ạ
PHP:
Function ExtractNumber(ByVal txt As String, ByVal N As Long) As Double
    Dim I As Long, strTemp As String, atmp, Str As String
txt = Replace(txt, ",", ".")
For I = 1 To Len(txt)
    Select Case Asc(Mid(txt, I, 1))
        Case 40 To 57, 94
            strTemp = strTemp & Mid(txt, I, 1)
        Case Else
            strTemp = strTemp & " "
    End Select
    Str = Application.Trim(strTemp)
    atmp = Split(Str, " ")
    If UBound(atmp) > N - 1 Then Exit For
Next I
If Len(Str) Then ExtractNumber = Val(Split(Str, " ")(N - 1))
End Function
 
Upvote 0
Dạ. Cám ơn Anh rất nhiều. Em sửa lại như thế này có được không ạ
PHP:
Function ExtractNumber(ByVal txt As String, ByVal N As Long) As Double
    Dim I As Long, strTemp As String, atmp, Str As String
txt = Replace(txt, ",", ".")
For I = 1 To Len(txt)
    Select Case Asc(Mid(txt, I, 1))
        Case 40 To 57, 94
            strTemp = strTemp & Mid(txt, I, 1)
        Case Else
            strTemp = strTemp & " "
    End Select
    Str = Application.Trim(strTemp)
    atmp = Split(Str, " ")
    If UBound(atmp) > N - 1 Then Exit For
Next I
If Len(Str) Then ExtractNumber = Val(Split(Str, " ")(N - 1))
End Function
Đây là 1 cách, bạn tham khảo.
Mã:
Function ExtractNumber(ByVal txt As String, ByVal N As Long) As Long
Dim i As Long, Str As String
For i = 1 To Len(txt)
    If IsNumeric(Mid(txt, i, 1)) Then
        Str = Str & Mid(txt, i, 1)
    ElseIf Len(Str) Then
        If N = 1 Then Exit For
        N = N - 1:  Str = ""
    End If
Next
If N = 1 Then ExtractNumber = VBA.CLng(0 & Str)
End Function
 
Upvote 0
Đây là 1 cách, bạn tham khảo.
Mã:
Function ExtractNumber(ByVal txt As String, ByVal N As Long) As Long
Dim i As Long, Str As String
For i = 1 To Len(txt)
    If IsNumeric(Mid(txt, i, 1)) Then
        Str = Str & Mid(txt, i, 1)
    ElseIf Len(Str) Then
        If N = 1 Then Exit For
        N = N - 1:  Str = ""
    End If
Next
If N = 1 Then ExtractNumber = VBA.CLng(0 & Str)
End Function
Cái Code này nó coi dấu "." hoặc dấu "," là kiểu chuỗi ạ
Ví dụ chuỗi tại ô A1 là: AA123.35bbb235
+ ExtractNumber(A1,1) =123
+ ExtractNumber(A1,2)=35
+ ExtractNumber(A1,3)=235
 
Upvote 0
Cái Code này nó coi dấu "." hoặc dấu "," là kiểu chuỗi ạ
Ví dụ chuỗi tại ô A1 là: AA123.35bbb235
+ ExtractNumber(A1,1) =123
+ ExtractNumber(A1,2)=35
+ ExtractNumber(A1,3)=235
Tôi làm theo dữ liệu bài 1 mà. Nếu muốn số thập phân thì sửa lại như sau:
Mã:
Function ExtractNumber(ByVal txt As String, ByVal N As Long, DecimalSep As String) As Double
Dim i As Long, Str As String
For i = 1 To Len(txt)
    If IsNumeric(Mid(txt, i, 1)) Then
        Str = Str & Mid(txt, i, 1)
    ElseIf Mid(txt, i, 1) = DecimalSep Then
        If Len(Str) Then Str = Str & Mid(txt, i, 1)
    ElseIf Len(Str) Then
        If N = 1 Then Exit For
        N = N - 1:  Str = ""
    End If
Next
If N = 1 Then ExtractNumber = CDbl(Replace(0 & Str, DecimalSep, "."))
End Function
Mã:
=ExtractNumber(A1,1,".")
 
Upvote 0
Tôi làm theo dữ liệu bài 1 mà. Nếu muốn số thập phân thì sửa lại như sau:
Mã:
Function ExtractNumber(ByVal txt As String, ByVal N As Long, DecimalSep As String) As Double
Dim i As Long, Str As String
For i = 1 To Len(txt)
    If IsNumeric(Mid(txt, i, 1)) Then
        Str = Str & Mid(txt, i, 1)
    ElseIf Mid(txt, i, 1) = DecimalSep Then
        If Len(Str) Then Str = Str & Mid(txt, i, 1)
    ElseIf Len(Str) Then
        If N = 1 Then Exit For
        N = N - 1:  Str = ""
    End If
Next
If N = 1 Then ExtractNumber = CDbl(Replace(0 & Str, DecimalSep, "."))
End Function
Mã:
=ExtractNumber(A1,1,".")
Hay là mình tìm cái dấu thập phân bằng lệnh này ạ: Application.DecimalSeparator
 
Upvote 0
Em là thành viên mới tham gia và thấy VBA thật quan trọng và tuyệt vời và đang muốn học để mở rộng kiến thức! mong các anh chị chỉ bảo địa điểm có thể dăng ký học từ cơ bản được không ạ. em ở gò vấp có địa điểm nào gần đây dạy ngoài giờ không các anh chị!
 
Upvote 0
Hay là mình tìm cái dấu thập phân bằng lệnh này ạ: Application.DecimalSeparator
Giả sử bạn đưa code đó vào file, dùng công thức trên sheet sau đó chuyển file cho người khác họ mở trên máy có thiết lập khác thì điều gì sẽ xảy ra?
 
Upvote 0
Upvote 0
Web KT

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

Back
Top Bottom