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!
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?
Vâng, đúng là em rất thận trọng trong việc viết code, em cũng cố gắng tìm cách cho ngắn nhưng không được anh à. Tiêu chí viết code của em là
+ An toàn (tính ổn định, lường trước các tình huống <>)
+ Tốc độ (Không để máy tính thừa các phép tính, lãng phí tài nguyên. Không dùng Split niều hơn một lần trên một biến,...)
+ Rõ ràng (Đọc dễ hiểu, không viết gộp nhiều lệnh vào một dòng)
+ Đạt được 3 tiêu chí trên mà code ngắn gọn thì càng tốt. Thường là khó thực hiện vì phải kiểm tra nhiều tình huống.
Vấn đề code dài hay ngắn không quan trọng mà 3 tiêu chí em liệt kê trên mới quan trọng.
Em đã hoàn thành hàm TextFromTo
Cấu trúc hàm:
TextFromTo(cText As String [, LengthCode As Long = 0] )
[COLOR="SeaGreen"]'--------------------------------------------------------------------
'Author: Nguyen Duy Tuan - www.bluesofts.net
'Prototype: [B]TextFromTo(cText As String [, LengthCode As Long = 0] )[/B]
'Purpose:
'cText = "150001-3,15,16,28-29"
'TextFromTo (cText)="150001,150002,150003,150015,150016,150028,150029"
'--------------------------------------------------------------------[/COLOR]
Option Explicit
Dim cFirstValue$, cText1$, lNum&
Function TextFromTo(ByVal cText As String, Optional ByVal LengthCode As Long = 0) As String
Dim ArrText
Dim lb&, ub&, I&, P1&
Dim cFirstValue2$, cTextRet$
Dim FirstNum&, Allow As Boolean
'cText = "150001-3,15,16,28-29"
ArrText = Split(cText, ",")
lb = LBound(ArrText, 1)
ub = UBound(ArrText, 1)
ArrText(lb) = Trim(ArrText(lb)): ArrText(ub) = Trim(ArrText(ub))
cFirstValue = Trim(ArrText(lb))
P1 = InStr(cFirstValue, "-")
If P1 > 0 Then cFirstValue = Left$(cFirstValue, P1 - 1)
If Len(cFirstValue) > 0 Then FirstNum = ExtractNum(cFirstValue, lNum)
If FirstNum > 1 Then
cText1$ = Left(cFirstValue, FirstNum - 1)
Else
cText1$ = ""
End If
If lb = ub And ArrText(lb) <> "" Then
TextFromTo = GetText(cFirstValue, cText1, lNum, ArrText(lb), LengthCode)
Exit Function
End If
For I = lb To ub
ArrText(I) = Trim(ArrText(I))
Allow = ArrText(I) <> ""
If LengthCode > 0 And TextFromTo = "" Then
Allow = Allow And (Len(ArrText(I)) >= LengthCode)
End If
If Allow Then
cFirstValue2 = ArrText(I)
P1 = InStr(cFirstValue2, "-")
If P1 > 0 Then
cFirstValue2 = Left$(cFirstValue2, P1 - 1)
If Len(cFirstValue2) >= Len(cFirstValue) And (cFirstValue2 <> cFirstValue) Then
cTextRet = TextFromTo(ArrText(I), LengthCode)
GoTo lbTextRet:
ElseIf LengthCode > 0 And Len(cFirstValue2) >= LengthCode Then
cTextRet = TextFromTo(ArrText(I), LengthCode)
GoTo lbTextRet:
End If
End If
cTextRet = GetText(cFirstValue, cText1, lNum, ArrText(I), LengthCode)
lbTextRet:
If cTextRet <> "" Then
TextFromTo = TextFromTo & IIf(TextFromTo <> "", ",", "") & cTextRet
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, ByVal LengthCode As Long) As String
Dim ArrText
Dim cText$
Dim I&, lb&, ub&, lNum1&, lNum2&
Dim nLenthText&
If LengthCode > 0 Then
nLenthText = LengthCode
Else
nLenthText = Len(cFirstValue)
End If
ArrText = Split(cSubText, "-")
lb = LBound(ArrText, 1)
ub = UBound(ArrText, 1)
ArrText(lb) = Trim(ArrText(lb))
ArrText(ub) = Trim(ArrText(ub))
If (ub - lb = 0) Then
If (ArrText(lb) = cFirstValue) Then
GetText = Trim(ArrText(lb))
Else
If IsNumeric(ArrText(ub)) Then
lNum2 = CLng(ArrText(ub))
If lNum2 < lNum Then lNum2 = GetMax(lNum, lNum2)
GetText = FillName(nLenthText, cFirstText, CStr(lNum2))
Else
GetText = FillName(nLenthText, cFirstText, ArrText(ub))
End If
End If
Exit Function
ElseIf ArrText(lb) = cFirstValue Then
ExtractNum ArrText(ub), lNum2
If lNum2 < lNum Then lNum2 = GetMax(lNum, lNum2)
For I = lNum To lNum2
cText = FillName(nLenthText, cFirstText, CStr(I))
GetText = GetText & IIf(GetText <> "", ",", "") & cText
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 = GetMax(lNum, lNum1)
If lNum2 < lNum Then lNum2 = GetMax(lNum, lNum2)
For I = lNum1 To lNum2
cText = FillName(nLenthText, cFirstText, CStr(I))
GetText = GetText & IIf(GetText <> "", ",", "") & cText
Next I
End Function
'--------------------------------------------------------------------
Function ExtractNum(ByVal cNum As String, ByRef lNum As Long) As Long
Dim I&
If IsNumeric(cNum) Then
lNum = CLng(cNum)
GoTo EndFunc:
End If
For I = Len(cNum) To 1 Step -1
If Not IsNumeric(Mid(cNum, I)) Then
ExtractNum = I
Exit For
End If
Next I
ExtractNum = ExtractNum + 1 'Possition of the first num
lNum = CLng(Mid(cNum, ExtractNum))
EndFunc:
End Function
'--------------------------------------------------------------------
Function GetMax(ByVal lNum As Long, lNum2 As Long) As Long
Dim nLen&, nLen2&
nLen = Len(CStr(lNum)): nLen2 = Len(CStr(lNum2))
If lNum2 < lNum And nLen2 < nLen Then
GetMax = CLng(Left$(lNum, nLen - nLen2) & lNum2)
Else
GetMax = lNum2
End If
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
ElseIf Len(Text2) >= nLengthText Then
FillName = Text2
Else
FillName = Text1 & Text2
End If
End Function
Rất cám ơn Tuân, làm quá tổng quát.
Yêu cầu của mình là: biến là 2 ký tự đầu + 4 ký tự kế tiếp = 6
1,, x,aa0001-3,151001-3, 150,16,200028-29,,,
Thì yêu cầu là aa0001,aa0002,aa0003,151001,151002,151003,151150,151016,200028,200029
Phần aa thiếu 1 ký tự mình tự sửa cũng OK.
Cám ơn nhiều.
Tạm thời sửa UDF của NDU chạy thử. Và test tiếp.
PHP:
Function ConvertText(Chuoi As String) As String
'***NDU96081631-GPE***'
Dim Temp As String, Pref As String, i As Long, j As Long, k As Long, Item, Arr
Dim iText1 As String, iText2 As String
On Error Resume Next
Chuoi = 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), 2)
If InStr(Arr(k), "-") Then
'kiem tra doan nay'
iText1 = Right(Split(Arr(k), "-")(0), 4)
iText2 = Split(Arr(k), "-")(1)
iText2 = Left(iText1, Len(iText1) - Len(iText2)) & iText2
For i = iText1 To iText2
Temp = Temp & ", " & Pref & Format(i, "0000")
Next i
Else
Temp = Temp & ", " & Pref & Format(Right(Arr(k), 4), "0000")
End If
Next k
ConvertText = Mid(Temp, 3, Len(Temp))
End Function
Function ConvertText(Chuoi As String) As String
'***NDU96081631-GPE***'
Dim Temp As String, Pref As String, i As Long, j As Long, k As Long, Item, Arr
Dim iText1 As String, iText2 As String
On Error Resume Next
Chuoi = 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), 2)
If InStr(Arr(k), "-") Then
'kiem tra doan nay'
iText1 = Right(Split(Arr(k), "-")(0), 4)
iText2 = Split(Arr(k), "-")(1)
iText2 = Left(iText1, Len(iText1) - Len(iText2)) & iText2
For i = iText1 To iText2
Temp = Temp & ", " & Pref & Format(i, "0000")
Next i
Else
Temp = Temp & ", " & Pref & Format(Right(Arr(k), 4), "0000")
End If
Next k
ConvertText = Mid(Temp, 3, Len(Temp))
End Function
Hàm của anh NDU96081631 rất ngắn gọn, khi em test trên 8 dạng/trường hợp trên thì bị sai ởi dạng 4, 5, 7 , các dạng còn lại chỉ đúng khi mã là 6 ký tự.
Nếu anh NDU96081631 hoàn thiện thêm thì rất tốt, các thành viên có thêm nhiều ví dụ để tham khảo, có nhiều dạng để áp dụng tổng quát, không chỉ cho nhu cầu anh ThuNghi.
Hàm của anh NDU96081631 rất ngắn gọn, khi em test trên 8 dạng/trường hợp trên thì bị sai ởi dạng 4, 5, 7 , các dạng còn lại chỉ đúng khi mã là 6 ký tự.
Nếu anh NDU96081631 hoàn thiện thêm thì rất tốt, các thành viên có thêm nhiều ví dụ để tham khảo, có nhiều dạng để áp dụng tổng quát, không chỉ cho nhu cầu anh ThuNghi.
Vâng! Tới đây là mình cũng sắp quá tải rồi...
Mình cũng đã nói từ đầu, mình mới tập tành thôi, vã lại yêu cầu của ThuNghi mang tính chuyên ngành gì đó mình chưa thấu hiểu nên cũng không thể lường trước được các trường hợp có thể xảy ra (đối với nhu cầu của người dùng)
Cảm ơn bạn Tuân đã cho mình mở rộng tầm mắt về kỹ thuật xử lý code
V. Tiêu chí viết code của em là
+ An toàn (tính ổn định, lường trước các tình huống <>)
+ Tốc độ (Không để máy tính thừa các phép tính, lãng phí tài nguyên. Không dùng Split niều hơn một lần trên một biến,...)
+ Rõ ràng (Đọc dễ hiểu, không viết gộp nhiều lệnh vào một dòng)
+ Đạt được 3 tiêu chí trên mà code ngắn gọn thì càng tốt. Thường là khó thực hiện vì phải kiểm tra nhiều tình huống. Vấn đề code dài hay ngắn không quan trọng mà 3 tiêu chí em liệt kê trên mới quan trọng.
Đó thành tiêu chí phần mềm rồi TUÂN ơi,
Còn ở đây là giải pháp
vòng đời của giải pháp có khi ngắn và dùng xử lý tình huống,
vì thế không nên câu nệ trong giải pháp quá?
Đó thành tiêu chí phần mềm rồi TUÂN ơi,
Còn ở đây là giải pháp
vòng đời của giải pháp có khi ngắn và dùng xử lý tình huống,
vì thế không nên câu nệ trong giải pháp quá?
Anh cho đó là giải pháp tạm thời hay là một giải pháp gì đi nữa thì tính an toàn trong giải pháp được đặt lên hàng đầu. Một chương trình đc xây dựng nên bởi hệ thống các thủ tục, hàm, nếu trong mỗi chúng (đặc biệt ở những khâu xử lý quan trọng) chúng ta làm không trọn vẹn (có nghĩa là chưa xử lý đc nhiều tính huống khác) dẫn đến cả một chương trình lỗi.
Cứ hình dung mấy cái chuỗi kia của bác ThuNghi nó được liệt kê thành chứng từ kế toán đó, là tiền, là quan hệ giao dịch của công ty đó. Điều gì xảy ra nếu các chứng từ được chạy hàm thiếu hoặc sai trong khi ta tưởng chạy hàm là đúng?
Ví dụ thứ hai là, em viết hàm để làm số chứng từ tự động (phiếu thu, chi, nhập ,xuất). Bình thường chạy vẫn đúng, sang tháng sau mở quyển chứng từ 2, vẫn nhập số chứng từ đó, chương trình báo lỗi trùng chứng từ không cho nhập (CT1 = CT1->lỗi; quyển 1.CT1 <> quyển 2. CT1). Đó, một hàm thôi sẽ làm hỏng cả một chương trình.
...
Thực sự có rất nhiều tính huống lỗi có thể xảy ra nên việc của người viết mã phải cố gắng làm cẩn thận một cách tối đa.
Thực ra trong công việc em cũng đã từng chịu hậu quả về những việc làm ẩu rồi nên giờ cẩn thận hơn thôi.