Thêm 1 bài toán tách chuổi (câu hỏi từ ddth.com)

Liên hệ QC
Ver 5 lun cho khác biệt

Để ý rằng việc khác "LOẠI" (1 or <>1) chỉ khác nhau đ/k => có thể dồn code như sau, thêm biến Dk1 và Dk2 --> Ngắn gọn hơn

ta có VER5
(vì Ver4 k hay nên bỏ rùi)

PHP:
Option Explicit

Function ExtrStr5(Mystr As String, sttchuoi As Byte, Loai As Byte) As String
Dim Kqtam As String, kQ As String, Lenst As Byte, newStr2 As String
Dim Dk1 As Boolean, Dk2 As Boolean
Dim i As Byte, j As Byte, tam As String, tam2 As String
kQ = ""
newStr2 = Mystr
For j = 1 To sttchuoi
  If Len(newStr2) = 0 Then
        ExtrStr5 = "": Exit Function
  Else
  Kqtam = ""
  Lenst = Len(newStr2)
  For i = 1 To Lenst
    tam = Mid(newStr2, i, 1)
    tam2 = " ": If i <= Len(newStr2) - 1 Then tam2 = Mid(newStr2, i + 1, 1)
    
    If Loai = 1 Then
            Dk1 = Asc(tam) <> 63:   Dk2 = Asc(tam2) = 63
    Else:   Dk1 = Asc(tam) = 63:    Dk2 = Asc(tam2) <> 63: End If
    
    If Dk1 Then
        Kqtam = Kqtam & tam
        If i <= Lenst - 1 Then
            If Dk2 Then
                newStr2 = Right(newStr2, Len(newStr2) - i): Exit For: End If
        Else: newStr2 = "": End If
     End If
     
  Next i
  kQ = Kqtam
  End If
Next j
ExtrStr5 = kQ
End Function
 
Lần chỉnh sửa cuối:
Hay nắm!
Nhân tiện cho hỏi:
2 cái này giống nhau:
1. If i <= Len(newStr2) - 1

2. If i < Len(newStr2)


Nhưng khi xài (2) thì bị lỗi khi chuỗi con cần tách ngắn hơn 7 ký tự. Lúc chiều làm bị lỗi tìm khắp mọi dòng code không rachỗ sai, thử xài (1) thì hết.
Là tại mần răng?
Xem file và giải thích giùm nhe Tiger!
 

File đính kèm

  • ExtractString(1).xls
    39.5 KB · Đọc: 21
Để ý rằng việc khác "LOẠI" (1 or <>1) chỉ khác nhau đ/k => có thể dồn code như sau, thêm biến Dk1 và Dk2 --> Ngắn gọn hơn
ta có VER5
(. . .) . . . .
Mình mới có í tưởng giảm thời lượng thêm 1/3, nếu
* Các kí tự Trung hoa (TrH) đều '?' thì
Khi gặp kí tự la tin đầu tiên tiếp theo, ta có thể tìm các kí tự TrH tiếp sau bằng hàm InStr()

Xin các bạn cho í kiến!
 
Hay nắm!
Nhân tiện cho hỏi:
2 cái này giống nhau:
1. If i <= Len(newStr2) - 1

2. If i < Len(newStr2)


Nhưng khi xài (2) thì bị lỗi khi chuỗi con cần tách ngắn hơn 7 ký tự. Lúc chiều làm bị lỗi tìm khắp mọi dòng code không rachỗ sai, thử xài (1) thì hết.
Là tại mần răng?
Xem file và giải thích giùm nhe Tiger!

chính xác là
1. If i <= Lenst - 1

2. If i < Lenst


GIờ mới để ý mới thật đúng là lạ, NHƯNG

Tìm ra lý do => đó là vì a ptm đã khai báo Lenst có kiểu là string =>
+ khi Lenst-1 => sẽ cho giá trị số
+ còn nếu để Lenst không thì => kq lưu có giá trị string --> LỖI

Giải pháp nếu thay 2) thế này thì OK: 2. If i < Lenst+0

Hoặc đổi lại khai báo biến Lenst as Byte

vì thế xin các bạn dùng sửa lun cả ở VER3 và 5 với khai báo biết Lenst As Byte
(mặc dù VER5 k bị sai vì có xử lý theo đ/k)

TigerTiger sẽ sửa lại các bài viết (VER3, VER5) trên sau bài viết này mấy tiếng (để mọi thành viên nhìn thấy sự nhầm lẫn này đã) __ Đã sửa lại bài
 
Lần chỉnh sửa cuối:
Nguyên văn bởi ptm0412
Nhân tiện cho hỏi:
2 cái này giống nhau:
1. If i <= Len(newStr2) - 1

2. If i < Len(newStr2)
Nhưng khi xài (2) thì bị lỗi khi chuỗi con cần tách ngắn hơn 7 ký tự. Lúc chiều làm bị lỗi tìm khắp mọi dòng code không rachỗ sai, thử xài (1) thì hết.
Là tại mần răng?
Xem file và giải thích giùm nhe Tiger!
Đọc file của bạn, tìm mãi không có các dòng lệnh trên. Chỉ thấy như sau:
Mã:
Function ExtrStr3(Mystr As String, sttchuoi As Byte, Loai As Byte) As String
Dim Kqtam As String, kQ As String, Lenst As String, newStr2 As String
newStr2 = Mystr
For j = 1 To sttchuoi
  If Len(newStr2) = 0 Then
        ExtrStr3 = "": Exit Function
  Else
  Kqtam = ""
  Lenst = Len(newStr2)
  For i = 1 To Lenst
    tam = Mid(newStr2, i, 1)
    If Loai = 1 And Asc(tam) <> 63 Then
            Kqtam = Kqtam & tam
            [B]If i < Lenst Then[/B]
                tam2 = Mid(newStr2, i + 1, 1)
                If Asc(tam2) = 63 Then
                    newStr2 = Right(newStr2, Len(newStr2) - i): Exit For
                End If
            Else: newStr2 = "": End If
    End If
    
    If Loai <> 1 And Asc(tam) = 63 Then
            Kqtam = Kqtam & tam
            [B]If i <= Lenst - 1 Then[/B]
                tam2 = Mid(newStr2, i + 1, 1)
                If Asc(tam2) <> 63 Then
                    newStr2 = Right(newStr2, Len(newStr2) - i): Exit For
                End If
            Else: newStr2 = "": End If
    End If
  Next i
  kQ = Kqtam
  End If
Next j
ExtrStr3 = kQ
End Function
-Câu lệnh If i < Lenst Then sẽ gây lỗi do khai báo biến Lenst ở dạng chuỗi. Điều kiện = false, newStr2 = "", dẫn đến lỗi.
-Câu lệnh If i <= Lenst - 1 Then không gây lỗi vì phép trừ Lenst - 1 cho ra một giá trị số. Điều kiện = True. Code chạy bình thường.
-Để kiểm tra, có thể khai báo lại biến hoặc thêm vào như sau: If i < Lenst - 0 Then.
 
Đọc file của bạn, tìm mãi không có các dòng lệnh trên. Chỉ thấy như sau:
-Câu lệnh If i < Lenst Then sẽ gây lỗi do khai báo biến Lenst ở dạng chuỗi. Điều kiện = false, newStr2 = "", dẫn đến lỗi.
-Câu lệnh If i <= Lenst - 1 Then không gây lỗi vì phép trừ Lenst - 1 cho ra một giá trị số. Điều kiện = True. Code chạy bình thường.
-Để kiểm tra, có thể khai báo lại biến hoặc thêm vào như sau: If i < Lenst - 0 Then.

Oh, post xong thì nhìn lại thấy bài viết Voda

Oh, ý tưởng trùng nhau rùi, NHƯNG NÊN SỬA LẠI LÀ KHAI BÁO BIẾN

Dim Lenst As Byte

Chi chuẩn xác hơn bác Voda ah,
 
Nhân nói về vụ khai báo biến tôi xin "ké" vào 1 câu hỏi:
Trong trường hợp ta ko chắc chắn giá trị của biến thuộc loại gì thì ta Dim thế nào đây? Cho biến vào cell rồi lấy giá trị trong đó ra xài chăng?
 
-Thật vui khi mình không hẹn mà gặp. Cám ơn tigertiger nhé. Ý của mình là chỉ để kiểm tra xem đúng lỗi đó không. Mình hoàn toàn nhất trí với bạn. Khai báo biến kiểu byte là cách làm chuẩn xác nhất.
 
Thanks TigerTiger, Thanks Voda

TigerTiger sẽ sửa lại các bài viết (VER3, VER5) trên sau bài viết này mấy tiếng (để mọi thành viên nhìn thấy sự nhầm lẫn này đã)
Mình cũng sửa luôn.
À Ver2 cũng dzậy Tiger à. Tai hại quá nhỉ!
 
Sửa rồi!
nhưng vẫn còn thắc mắc: File lỗi bài #22, theo phân tích của Voda thì:
Câu lệnh If i < Lenst Then sẽ gây lỗi do khai báo biến Lenst ở dạng chuỗi. Điều kiện = false, newStr2 = "", dẫn đến lỗi.
nhưng nó chỉ lỗi ở cell C3 (file đính kèm bài #22) do "Bankok" dài 6 ký tự, còn các cell khác không bị lỗi. và mình nhận thấy 7 ký tự trở lên là không lỗi!
Nhờ Voda giải thích tiếp
 
Hàm Asc chỉ hiểu các ký tự có mã từ 1 đến 255 (như hàm CODE của Excel), gồm các ký tự thấy được và không thấy trên màn hình. Các ký tự thấy được gồm có:
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™
š›œžŸ ¡¢£¤¥¦§¨©ª«¬&shy;®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ
Bạn chú ý trong các ký tự trên 32 ký tự tiếng Việt có dấu.
Các ký tự có mã > 255 bị chuyển sang dấu ? nên Asc cho kết quả là 63 (mã của dấu ?). Các bạn thường thấy dấu hỏi này khi nhập ký tự tiếng Việt trong VBA như di?n ?àn gi?i pháp Excel.
Tiếng Việt có dấu được phân bổ như sau:
- 32 ký tự trong khoảng 192 > 253 (hàm Asc nhận biết được)
- 12 ký tự trong khoảng 242 > 420
- 90 ký tự trong khoảng 7840 > 7929
Mỗi ngôn ngữ được Microsoft phân bổ trên một hoặc nhiều vùng của bảng mã Unicode. Ví dụ ký tự trong chuỗi 马来西亚Malaysia吉隆坡Kuala Lumpur có mã 26469 (không biết là TQ, Nhật hay Hàn?). Các ký tự mình gọi là tiếng miên thì mã của nó phải > 255.
Do đó, dùng hàm Asc trong các hàm mà các bạn đã viết chỉ có khả năng tách các ký tự ra 2 nhóm:
Latinh: <=255 (có lai một số ký tự không phải latinh)
Đa ngôn ngữ: >255 (Việt, Á rập, Nga, TQ, Hàn, Nhật, ...)
Do ví dụ minh họa là 马来西亚Malaysia吉隆坡Kuala Lumpur nên các bạn nghĩ là nó tách được Latinh và TQ.
 
Nếu thế thì bổ sung chi tiết thế này

theo UNICODE Standard (theo http://unicode.org/standard/standard.html ) thì:
Cham: U+AA00—U+AA5F

Cham is an Austronesian language used in Vietnam and Cambodia. There are two main groups, the Eastern Cham and the Western Cham; the script is used more by the Eastern Cham. It is a complex, Brahmic script and uses combining marks.
Cham has script-specific digits, although European digits are also used. It also has some script-specific punctuation, although, again, Western punctuation is also used. Opportunities for linebreak occur after any full orthographic syllable. Spaces are used between words.


và tham khảo thêm: http://en.wikipedia.org/wiki/Unicode
 
Lần chỉnh sửa cuối:
Nguyên văn bởi ptm0412
nhưng nó chỉ lỗi ở cell C3 (file đính kèm bài #22) do "Bankok" dài 6 ký tự, còn các cell khác không bị lỗi. và mình nhận thấy 7 ký tự trở lên là không lỗi
Theo mình, tình trạng gây lỗi ở cả 2 hàm đều do sự khai báo biến. Nguyên nhân cụ thể của nó như sau:
-Câu lệnh: If i < Lenst Then ...(Lenst là biến chuỗi)
+ Sẽ false khi i có giá trị từ 1-9.
+Sẽ true khi i có giá trị >= 10.
-Lỗi ở cell C3 là do chữ Bankok có 6 ký tự + 4 ký tự chữ TQ phía trước =10. Bạn chỉ cần thêm 1 ký tự TQ phía trước là hết lỗi ngay.
-Từ đó ta có thể khái quát nếu tổng ký tự TQ+LT> 10 ---> không bị lỗi.
 
Lỗi do khai báo biến thì mình hiểu rồi, nhưng hậu quả của khai báo biến sai thì lại không hiểu được:
-Câu lệnh: If i < Lenst Then ...(Lenst là biến chuỗi)
+ Sẽ false khi i có giá trị từ 1-9.
+Sẽ true khi i có giá trị >= 10.
-Lỗi ở cell C3 là do chữ Bankok có 6 ký tự + 4 ký tự chữ TQ phía trước =10. Bạn chỉ cần thêm 1 ký tự TQ phía trước là hết lỗi ngay.
-Từ đó ta có thể khái quát nếu tổng ký tự TQ+LT> 10 ---> không bị lỗi.

Đó là hiện tượng, thế còn nguyên nhân?
Nguyên nhân nào để 1 số nhỏ hơn 10, không so sánh >, <, = với 1 chuỗi, còn 1 số từ 10 trở lên thì so sánh được?
 
Nguyên văn bởi ptm0412
Đó là hiện tượng, thế còn nguyên nhân?
-Trước mắt là ghi nhận hiện tượng để giải thích: vì sao chuỗi la tinh nhỏ hơn 7 ký tự, code chạy sai, còn 7 ký tự trở lên, code chạy đúng? Còn nguyên nhân thế nào thì mình chưa hiểu được.
Nguyên nhân nào để 1 số nhỏ hơn 10, không so sánh >, <, = với 1 chuỗi, còn 1 số từ 10 trở lên thì so sánh được?
Không phải số nhỏ hơn 10 nó không so sánh mà so sánh hơn. i = 7, Lenst = 47, If i < Lenst Then =false có nghĩa là 7 > 47!
 
Theo mình thì khi chuỗi la tinh nhỏ hơn 7 ký tự, nó bỏ qua so sánh, code chạy tiếp cho kết quả bankokMalaysia,
Khi chuỗi latinh có số ký tự từ 7 trở lên, nó so sánh được, cho giá trị False hoặc True tuỳ theo i và đúng với Is i < LenSt

Thôi, tốt nhất là khai báo biến cho đúng! :-=
---------
Lý luận này sai rồi, xem bài của Bác Voda bên dưới.
 
Lần chỉnh sửa cuối:
-Bạn đã thử thêm ký tự vào chuỗi TQ phía trước chưa? Nếu thêm 2 ký tự thì "Banko" vẫn cho kết quả đúng.
-Mình đã tách và cho chạy riêng đoạn code ấy. Cho Lenst có giá trị 50. Biến i chạy từ 0 đến 10000. Sau đây là kết quả:
............-i từ 0-5: nhỏ hơn Lenst
............-5-9: lớn hơn
........... .-10-49: nhỏ hơn
............-50 : bằng
............-51-99: lớn hơn
............-100-499: nhỏ hơn
............-500-999: lớn hơn
............-1000-4999: nhỏ hơn
............-5000-9999:lớn hơn
............-10000 : nhỏ hơn.
Nếu thay giá trị Lenst, ta thấy sự so sánh lớn, nhỏ cũng biến đổi theo chu kỳ như thế.
Điều này chứng tỏ rằng dù Lenst được khai báo dạng chuỗi thì code vẫn chạy đúng trong một giới hạn nào đó của biến i.
- Nếu Lenst = 20 thì code chạy đúng khi i trong khoảng 10 - 19.
-Nếu Lenst bằng 30 thì code chạy đúng khi i từ 10 - 29...
-Và tất nhiên trong các khoảng khác nữa ( theo kết quả trên)
Nhờ các bạn giải thích dùm hiện tượng này. Vậy Lenst là số hay chuỗi? Nếu là chuỗi, lúc nào Lenst cũng phải lớn hơn i. Nếu là số, tại sao có lúc lớn, lúc nhỏ? Vì sao so sánh lớn nhỏ diễn ra theo một chu kỳ nhất định?
 
Bác Voda đã test kỹ vậy thì đúng quá rồi. Thanks bác.
Từ đó luận ra theo code:

PHP:
        If i < Lenst Then
            If Asc(tam2) = 63 Then
            Newstr = Right(Mystr, Len(Mystr) - i)
            Exit For
            End If
        Else
        Newstr = ""

- i trong khoảng 5 -9: i > LenSt, Chuyển sang dòng lệnh Else: Newstr = "".
Nhưng code For đang chạy trên MyStr, chứ không phải NewStr, nên chạy tiếp nối thêm 1 chuỗi latin nữa vào kết quả.
- Sau đó i nằm trong khoảng 10 - 49: i < LenSt, chạy dòng lệnh Newstr = Right(Mystr, Len(Mystr) - i) và thoát For. Giá trị này lần sau mới dùng và trở thành MyStr của lần sau.

Thanks bác lần nữa.
 
Web KT
Back
Top Bottom