Chuyển 1 chuỗi thành chuỗi khác!

  • Thread starter Thread starter ThuNghi
  • Ngày gửi Ngày gửi
Liên hệ QC

ThuNghi

Hãy cho rồi sẽ nhận!
Thành viên đã mất
Tham gia
16/8/06
Bài viết
3,808
Được thích
4,449
Nhờ các cao thủ hay thấp thủ giúp tôi viết 1 UDF tách chuỗi sau thành 1 chuỗi khác.
Text1: 150001-3,15,16,28-29
Thành
Text2: 150001, 150002, 150003, 150015, 150016, 150028, 150029

Cụ thể:
150001-3 là 150001, 150002, 150003
...
Các chuỗi con luôn là 6 ký tự bắt đầu là 15 và tiếp là số 0.
Xin cám ơn!
 
Thử cái này xem nha ThuNghi, mua thêm Ken bỏ vào kho, ghi TK ptm
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Có sửa lại 1 tí:
2-3,8,...
Nghĩa là số nhỏ hơn 10, file trước bị sai. Vui lòng tải lại file bài trên.
Còn dấu phẩy cuối theo Thu Nghi cho biết thì không bao giờ có.
Các bẫy lỗi khác nếu có thì dễ, Thu Nghi tự làm được.
 
Upvote 0
Bác PTM triển khai thêm giúp
Text1: 150001-3,15,16,110028-29
Thành
Text2: 150001, 150002, 150003, 150015, 150016, 110028, 110029

Cụ thể:
150001-3 là 150001, 150002, 150003

110028-29 là 110028, 110029 số 1500, 1100 ở đầu là biến.

Nhờ các bạn làm giúp. Em đang tập tành viết UDF thôi.
Cám ơn nhiều!
 
Lần chỉnh sửa cuối:
Upvote 0
ThuNghi thử code này xem thế nào (làm đại)
PHP:
Function ConvertText(Chuoi As String) As String
  Dim Temp1, Temp2, Temp As String, Item, i As Long
  On Error Resume Next
  Temp1 = Split(Chuoi, ",")
  For Each Item In Temp1
    If Len(Item) > 5 Then Temp = Left(Item, 4)
    If InStr(Item, "-") Then
      For i = Mid(Item, InStr(Item, "-") - 2, 2) To Mid(Item, InStr(Item, "-") + 1, Len(Item))
        Temp2 = Temp2 & ", " & Temp * 100 + i
      Next i
    Else
      Temp2 = Temp2 & ", " & Temp * 100 + Item
    End If
  Next Item
  ConvertText = Mid(Temp2, 3, Len(Temp2))
End Function
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Cũng bị cái lỗi ban đầu như lỗi của lão chết tiệt, ndu ơi. Chuỗi này, có len(Item)<5 nên không thèm liệt kê:
150001-3, 5,7-9, 15,16,200028-29,,,
 
Upvote 0
Cũng bị cái lỗi ban đầu như lỗi của lão chết tiệt, ndu ơi. Chuỗi này, có len(Item)<5 nên không thèm liệt kê:
150001-3, 5,7-9, 15,16,200028-29,,,
Vậy em sửa lại tí:
PHP:
Function ConvertText(Chuoi As String) As String
  Dim Temp As String, Pref As String, i As Long, Item1, Item2
  On Error Resume Next
  For Each Item1 In Split(Chuoi, ",")
    If Len(Item1) > 5 Then Pref = Left(Item1, 4)
    If InStr(Item1, "-") Then
      For i = Right(Split(Item1, "-")(0), 2) To Right(Split(Item1, "-")(1), 2)
        Temp = Temp & ", " & Pref * 100 + i
      Next i
    Else
      Temp = Temp & ", " & Pref * 100 + Right(Item1, 2)
    End If
  Next Item1
  ConvertText = Mid(Temp, 3, Len(Temp))
End Function
 

File đính kèm

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

Gửi các bạn hàm TextFromTo
Hàm TextFromTo tôi viết đáp ứng cho nhu cầu tổng quát về tạo danh sách chuỗi mã theo chuỗi định nghĩa và khoảng giá trị xác định.

Các trường hợp sau có thể vận dụng được hàm TextFromTo
+ 150001-3,15,16,28-29
KQ: 150001,150002,150003,150015,150016,150028,150029

+ 00000-3,5-13,14,15-18,19
KQ: 00000,00001,00002,00003,00005,00006,00007,00008,00009,00010,00011,00012,00013,00014,00015,00016,00017,00018,00019

+ PT000-3,4-13,14,15-18,19
KQ: PT000,PT001,PT002,PT003,PT004,PT005,PT006,PT007,PT008,PT009,PT010,PT011,PT012,PT013,PT014,PT015,PT016,PT017,PT018,PT019

+ T100,1-2,3-5ABC, 6
KQ: T100,T101,T102,T106

Giá trị đầu tiên được lấy làm mẫu để tạo các mã trong danh sách.

Mã nguồn:
Mã:
''--------------------------------------------------------------------------
'Author: Nguyen Duy Tuan - www.bluesofts.net
'--------------------------------------------------------------------------
Option Explicit

Function TextFromTo(ByVal cText As String) As String
    Dim ArrText
    Dim lb&, ub&, I&, P1&
    Dim cFirstValue$, cText1$, cTextRet$
    Dim FirstNum&, lNum&

    'cText = "150001-3,15,16,28-29"
    ArrText = Split(cText, ",")
    
    lb = LBound(ArrText, 1)
    ub = UBound(ArrText, 1)
    
    cFirstValue = ArrText(lb)
    P1 = InStr(cFirstValue, "-")
    If P1 > 0 Then
        cFirstValue = Left$(cFirstValue, P1 - 1)
    End If
    
    For I = Len(cFirstValue) To 1 Step -1
        If Not IsNumeric(Mid(cFirstValue, I)) Then
            FirstNum = I
            Exit For
        End If
    Next I
    
    FirstNum = FirstNum + 1
    
    If FirstNum > 1 Then
        cText1$ = Left(cFirstValue, FirstNum - 1)
    Else
        cText1$ = ""
    End If
    
    lNum = CLng(Mid(cFirstValue, FirstNum))
    
    For I = lb To ub
        If ArrText(I) <> "" Then
            cTextRet = GetText(cFirstValue, cText1, lNum, ArrText(I))
            If cTextRet <> "" Then
                If TextFromTo = "" Then
                    TextFromTo = cTextRet
                Else
                    TextFromTo = TextFromTo & "," & cTextRet
                End If
            End If
        End If
    Next I
    
End Function
'--------------------------------------------------------------------------
Function GetText(ByVal cFirstValue As String, ByVal cFirstText As String, ByVal lNum As Long, ByVal cSubText As String) As String
    Dim ArrText
    Dim cText$
    Dim I&, lb&, ub&, lNum1&, lNum2&
    Dim nLenthText&
    
    nLenthText = Len(cFirstValue)
    
    ArrText = Split(cSubText, "-")
    
    lb = LBound(ArrText, 1)
    ub = UBound(ArrText, 1)
    
    If (ub - lb = 0) Then
        If (ArrText(lb) = cFirstValue) Then
            GetText = ArrText(lb)
        Else
            If IsNumeric(ArrText(ub)) Then
                lNum2 = CLng(ArrText(ub))
                If lNum2 < lNum Then lNum2 = lNum + lNum2 - IIf(lNum Mod 10 = 0, 0, 1)
                GetText = FillName(nLenthText, cFirstText, CStr(lNum2))
            Else
                GetText = FillName(nLenthText, cFirstText, ArrText(ub))
            End If
        End If
        Exit Function
    ElseIf ArrText(lb) = cFirstValue Then
        If IsNumeric(ArrText(ub)) Then
            lNum2 = CLng(ArrText(ub))
        End If
        If lNum2 < lNum Then lNum2 = lNum + lNum2 - IIf(lNum Mod 10 = 0, 0, 1)
        
        For I = lNum To lNum2
            cText = FillName(nLenthText, cFirstText, CStr(I))
            If I = lNum Then
                GetText = cText
            Else
                GetText = GetText & "," & cText
            End If
        Next I
        Exit Function
    End If
    
    If IsNumeric(ArrText(lb)) Then
        lNum1 = CLng(ArrText(lb))
    End If
    If IsNumeric(ArrText(ub)) Then
        lNum2 = CLng(ArrText(ub))
    End If
    
    If lNum1 < lNum Then lNum1 = lNum + lNum1 - 1 + IIf(lNum Mod 10 = 0, 1, 0)
    If lNum2 < lNum Then lNum2 = lNum + lNum2 - IIf(lNum Mod 10 = 0, 0, 1)
    
    For I = lNum1 To lNum2
        cText = FillName(nLenthText, cFirstText, CStr(I))
        If GetText <> "" Then
            GetText = GetText & "," & cText
        Else
            GetText = cText
        End If
    Next I
End Function
'--------------------------------------------------------------------------
Function FillName(ByVal nLengthText As Long, ByVal Text1 As String, ByVal Text2 As String, Optional ByVal CharToFill As String = "0")
    Dim nLen&
    nLen = Len(Text1) + Len(Text2)
    
    If nLen < nLengthText Then
        FillName = Text1 & String$(nLengthText - nLen, CharToFill) & Text2
    Else
        FillName = Text1 & Text2
    End If
End Function
 

File đính kèm

Upvote 0
Dựa trên căn bản: "Các chuỗi con luôn là 6 ký tự" (sic), với yêu cầu 2 là 4 số đầu thay đổi (1500, 1100, ...) thì code của ndu đúng hơn cả. Thuật toán so với lão chết tiệt thì giống nhưng ngắn gọn hơn vì dùng phương thức split.
Code của TuanVNUNI thì hay quá (đọc chưa hiểu), vượt yêu cầu bài #1 nhưng chưa áp dụng được cho yêu cầu 2.
 
Upvote 0
Dựa trên căn bản: "Các chuỗi con luôn là 6 ký tự" (sic), với yêu cầu 2 là 4 số đầu thay đổi (1500, 1100, ...) thì code của ndu đúng hơn cả. Thuật toán so với lão chết tiệt thì giống nhưng ngắn gọn hơn vì dùng phương thức split.
Code của TuanVNUNI thì hay quá (đọc chưa hiểu), vượt yêu cầu bài #1 nhưng chưa áp dụng được cho yêu cầu 2.

Các code trên nếu cho ký tự chữ đứng trước sẽ bị sai. Nên làm cho trường hợp tổng quát để những người khác cùng được áp dụng.

Em đang chỉnh lại code của em, sẽ up lên sau.
 
Upvote 0
Các code trên nếu cho ký tự chữ đứng trước sẽ bị sai. Nên làm cho trường hợp tổng quát để những người khác cùng được áp dụng.

Em đang chỉnh lại code của em, sẽ up lên sau.
Tuân ơi... Mình không dám nói code của Tuân không hay, nhưng cho dù là áp dụng với các ký tự chử đứng trước (như PT00...) thì mình nghĩ code cũng không đến nổi dài như thế... Cải tiến lại, 1 UDF duy nhất, ngắn cở 1/3 cái trên cũng đã đủ lắm rồi
Mình đang tập tành, có thể ý kiến còn quá chủ quan (do chưa hiểu hết ý đồ của tác giả) nên có gì chưa phải trong phát biểu mong bạn lượng thứ cho
Mình nghĩ vấn đề nằm ở chổ bạn quá cẩn thận trong việc viết code chẳng?
-----------------
Dựa trên căn bản: "Các chuỗi con luôn là 6 ký tự" (sic), với yêu cầu 2 là 4 số đầu thay đổi (1500, 1100, ...) thì code của ndu đúng hơn cả. Thuật toán so với lão chết tiệt thì giống nhưng ngắn gọn hơn vì dùng phương thức split.
Code của TuanVNUNI thì hay quá (đọc chưa hiểu), vượt yêu cầu bài #1 nhưng chưa áp dụng được cho yêu cầu 2.
Cái này em học từ sư phụ mà... Ẹc.. Ẹc..
 
Upvote 0
Tuân ơi... Mình không dám nói code của Tuân không hay, nhưng cho dù là áp dụng với các ký tự chử đứng trước (như PT00...) thì mình nghĩ code cũng không đến nổi dài như thế... Cải tiến lại, 1 UDF duy nhất, ngắn cở 1/3 cái trên cũng đã đủ lắm rồi
Mình đang tập tành, có thể ý kiến còn quá chủ quan (do chưa hiểu hết ý đồ của tác giả) nên có gì chưa phải trong phát biểu mong bạn lượng thứ cho
Mình nghĩ vấn đề nằm ở chổ bạn quá cẩn thận trong việc viết code chẳng?
-----------------

Cái này em học từ sư phụ mà... Ẹc.. Ẹc..
Rất cám ơn các Bác.
Code của ndu là OK rồi, do không mình không nêu rõ điều kiện.
150001-3,15,16,200028-29,,,
thành
150001, 150002, 150003, 150015, 150016, 200028, 200029
Là đáp ứng được yêu cầu.
Bây giờ mình triển khai thêm nhé, mong các Bác hoàn thiện tiếp tục.

1,, x,aa1001,151001-3, 15,16,200028-29,,,

Thành

aa1001,151001, 151002, 151003, 151015, 151016, 200028, 200029

Nghĩa là khi duyệt từ bên trái qua, nếu chuỗi con nào có đủ 6 ký tự thì nó sẽ làm đại diện cho group chuỗi kế tiếp cho đến khi nào gặp chuỗi mới.

Một lần nữa xin cám ơn Bác PTM, NDU, Tuân.
 
Upvote 0
Rất cám ơn các Bác.
Code của ndu là OK rồi, do không mình không nêu rõ điều kiện.
150001-3,15,16,200028-29,,,
thành
150001, 150002, 150003, 150015, 150016, 200028, 200029
Là đáp ứng được yêu cầu.
Bây giờ mình triển khai thêm nhé, mong các Bác hoàn thiện tiếp tục.



Thành



Nghĩa là khi duyệt từ bên trái qua, nếu chuỗi con nào có đủ 6 ký tự thì nó sẽ làm đại diện cho group chuỗi kế tiếp cho đến khi nào gặp chuỗi mới.

Một lần nữa xin cám ơn Bác PTM, NDU, Tuân.
Cùng lắm tôi thêm 1 vòng lập để kiểm tra, phát hiện ra Item nào có len() > 5 thì "tóm cổ" và bắt đầu làm việc từ vị trị này
PHP:
Function ConvertText(Chuoi As String) As String
  Dim Temp As String, Pref As String, i As Long, j As Long, k As Long, Item, Arr
  On Error Resume Next
  Chuoi = WorksheetFunction.Trim(Replace(Replace(Chuoi, " ", ""), ",", " "))
  Arr = Split(Chuoi, " ")
  For Each Item In Arr
    If Len(Item) > 5 Then Exit For
    j = j + 1
  Next Item
  For k = j To UBound(Arr)
    If Len(Arr(k)) > 5 Then Pref = Left(Arr(k), 4)
    If InStr(Arr(k), "-") Then
      For i = Right(Split(Arr(k), "-")(0), 2) To Right(Split(Arr(k), "-")(1), 2)
        Temp = Temp & ", " & Pref & Format(i, "00")
      Next i
    Else
      Temp = Temp & ", " & Pref & Right(Arr(k), 2)
    End If
  Next k
  ConvertText = Mid(Temp, 3, Len(Temp))
End Function
Tạm dùng được nhưng tôi vẫn thấy còn cải tiến thêm được nữa đấy
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Sorry!
Đoạn:
Temp = Temp & ", " & Pref & Right(Arr(k), 2)
phải sửa thành:
Temp = Temp & ", " & Pref & Format(Right(Arr(k), 2), "00")
thì mới đúng (ở trên đã Format rồi mà ở dưới lại quên)
Tôi post lại đây
 

File đính kèm

Upvote 0
Tiếp nữa nhé Bác NDU.
,,,PT0099-101, 150,16,200028-29,,,
thành

PT0099,PT0101,PT0150, PT0016, 200028, 200029
Ie
PT0099-101 thành PT0099,PT0101
Sau dấu "-" là bao nhiêu ký tự thì ta xét chuỗi trước dấu "-" theo len. Và nối vào theo tiêu chuẩn 2 ký đầu và "00000" cho đủ 6 ký tự.

Rất cám ơn. Bài toán đơn giản mà phát sinh nhiều vấn đề ghê.

Tks NDU tôi đã sửa lại code theo ý mình rồi. Xin phép được dùng code này vào công việc.
Công việc cụ thể như sau:
Chi 1.000.000 đ cho những số CT như sau: ,,,PT0099-101, 150,16,200028-29,,, và do lúc nhập không theo chuẩn nào hết nên bấy giờ làm bài toán ngược là chi cho chứng từ nào là bao nhiêu. Cũng vận dụng được đến đâu hay đến đó thôi.
Cám ơn sự giúp đỡ, và xin lỗi vì đã làm phiền.
 
Lần chỉnh sửa cuối:
Upvote 0
Sorry!
Đoạn:
Temp = Temp & ", " & Pref & Right(Arr(k), 2)
phải sửa thành:
Temp = Temp & ", " & Pref & Format(Right(Arr(k), 2), "00")
thì mới đúng (ở trên đã Format rồi mà ở dưới lại quên)
Tôi post lại đây

"00" - Trong trường hợp hợp 4, 3, và 2 chữ số thì sao nhỉ

Code này chỉ đúng với số có 2 chữ số
 
Upvote 0
"00" - Trong trường hợp hợp 4, 3, và 2 chữ số thì sao nhỉ

Code này chỉ đúng với số có 2 chữ số
Thì sửa luôn thành 4 vì 2 số đầu là biến, còn tiếp là 000001-99999.

Right(Split(Arr(k), "-")(0), 3) thành
Right(Split(Arr(k), "-")(0), 4)

Temp = Temp & ", " & Pref & Format(i, "0000")
 
Upvote 0
Web KT

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

Back
Top Bottom