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

Liên hệ QC

Người dùng đang xem chủ đề này

anhtuan1066

Thành viên gạo cội
Tham gia
10/3/07
Bài viết
5,802
Được thích
6,912
Tôi gặp 1 bài toán từ dtth.com, thấy hay nên post lên cho mọi người tham khảo... Nguyên văn như sau:
Em có một vấn đề nhỏ xíu không biết giải, đưa lên đây mong anh em chỉ giáo thêm...
trong 1 cell có 2 loại chữ như thế này: "马来西亚Malaysia吉隆坡Kuala Lumpur" bây giờ dùng hàm như thế nào để tách chữ Trung Quốc ra 1 cell khác và chữ LaTinh ra 1 cell khác.
Em học dzở excel mong mấy anh đừng chê cười...
Tôi đang định dùng vòng lập quét qua chuổi với điều kiên ký tự nào có code = 65~90 hoặc 97~122 thì lấy, ngược lại ký tự nào có hàm code trả về giá trị ko nằm trong 2 khoảng này thì bỏ qua!
Giã định rằng ký tự Latin là các ký tự thông thường ko chứa ký tự đặc biệt, và giã định thêm mỗi chuổi có cấu trúc tổng quát như sau: Trung quốc Latin Trung quốc Latin
Các cao thủ khác góp ý xem thử ta giãi quyết bài này như thế nào?
ANH TUẤN
 
Tôi gặp 1 bài toán từ dtth.com, thấy hay nên post lên cho mọi người tham khảo... Nguyên văn như sau:

Tôi đang định dùng vòng lập quét qua chuổi với điều kiên ký tự nào có code = 65~90 hoặc 97~122 thì lấy, ngược lại ký tự nào có hàm code trả về giá trị ko nằm trong 2 khoảng này thì bỏ qua!
Giã định rằng ký tự Latin là các ký tự thông thường ko chứa ký tự đặc biệt, và giã định thêm mỗi chuổi có cấu trúc tổng quát như sau: Trung quốc Latin Trung quốc Latin
Các cao thủ khác góp ý xem thử ta giãi quyết bài này như thế nào?
ANH TUẤN

Vấn đề nhỏ xíu mà chẳng nhỏ tí nào. Em thử lấy code() của mấy ký tự tiếng Hoa, nó toàn ra số 63 cả. Còn trong VB thì không ra được.
 
Vấn đề nhỏ xíu mà chẳng nhỏ tí nào. Em thử lấy code() của mấy ký tự tiếng Hoa, nó toàn ra số 63 cả. Còn trong VB thì không ra được.
Kết quả 63 đâu có sao đâu! Như tôi đã nói, chỉ cần lưu ý giá trị hàm code nào thuộc khoảng từ 65~90 hoặc từ 97~122 thì lấy... những cái ko thuộc khoảng này thì bỏ qua là dc rồi... Như vậy ta sẽ tách dc các ký tự Latin ra riêng, phần ký tự TQ có lẻ dùng các hàm cắt chuổi tương tự như SUBSTITUTE: mang chuổi gốc ra thay thế các ký tự Latin vừa tách ra = ký tự rỗng...
Bạn nghĩ sao?
ANH TUẤN
 
Các cao thủ cho hỏi! Tôi đang làm bài này bằng VBA nhưng bị vướng ở hàm CODE
Cho hỏi trong VBA cái gì thay thế hàm CODE vậy? Tôi dùng Application.WorksheetFunction.Code nó ko chịu... thậm chí dùng đến tuyệt chiêu:
Temp1 = Evaluate("=Code(.............)") giống như ta vẫn làm với hàm SUMPRODUCT trong VBA cũng ko ăn thua
Phải làm sao đây? Xin dc trợ giúp!
ANH TUẤN
 
Trong VBA ta dùng hàm Asc, Ví dụ : Asc("A") cho giá trị 65.
 
Tôi gặp 1 bài toán từ dtth.com, thấy hay nên post lên cho mọi người tham khảo... Nguyên văn như sau:

Tôi đang định dùng vòng lập quét qua chuổi với điều kiên ký tự nào có code = 65~90 hoặc 97~122 thì lấy, ngược lại ký tự nào có hàm code trả về giá trị ko nằm trong 2 khoảng này thì bỏ qua!
Giã định rằng ký tự Latin là các ký tự thông thường ko chứa ký tự đặc biệt, và giã định thêm mỗi chuổi có cấu trúc tổng quát như sau: Trung quốc Latin Trung quốc Latin
Các cao thủ khác góp ý xem thử ta giãi quyết bài này như thế nào?
ANH TUẤN

Hình như hum trước trên diễn đàn GPE đã có bài tương tự cũng về chữ Trung Quôc (chinnese), không biết giải quyết chưa nhỉ
ah, tìm thấy đây rùi: http://www.giaiphapexcel.com/forum/showthread.php?p=67884#post67884

Hướng giải quyết thế là được, Nhưng có vẻ hơi chậm (vì chúng ta phải dò từng ký tự, -> rồi nhặt từng ký tự)
 
Tôi thấy bài toán với dử liệu tôi đưa lên là hoàn toàn khả thi ấy chứ... Tôi làm bằng công thức tách ra dc tuốt, đáng tiếc là ko hợp lại dc theo kiểu như VBA:
Temp1 = Temp1 & Temp2
Chắn chắn VBA giãi quyết việc này trong tầm tay, nhưng tôi làm file bằng VBA cãm thấy vất vả quá! Các cao thủ giúp 1 tay với!
ANH TUẤN
 
Tôi thấy bài toán với dử liệu tôi đưa lên là hoàn toàn khả thi ấy chứ... Tôi làm bằng công thức tách ra dc tuốt, đáng tiếc là ko hợp lại dc theo kiểu như VBA:
Temp1 = Temp1 & Temp2
Chắn chắn VBA giãi quyết việc này trong tầm tay, nhưng tôi làm file bằng VBA cãm thấy vất vả quá! Các cao thủ giúp 1 tay với!
ANH TUẤN

Anh ANHTUANxem thử giải pháp của em xem. Có gì cho em ý kiến nhé!
Vui lòng xem file đính kèm
 

File đính kèm

Lần chỉnh sửa cuối:
OK... vậy là tuyệt lắm rồi... Từ đây nếu ai muốn tách chi tiết nữa thì hoàn toàn có thể dùng các hàm cắt chuổi thông thường...
Cảm ơn bạn!
ANH TUẤN
 
Nếu muốn tách riêng nhóm từ thứ n thì dùng hàm này: =ToLatin(chuỗi gốc, STT nhóm từ)
Code cũng đơn giản, và ngắn gọn.
 

File đính kèm

Nếu muốn tách riêng nhóm từ thứ n thì dùng hàm này: =ToLatin(chuỗi gốc, STT nhóm từ)
Code cũng đơn giản, và ngắn gọn.
Cách này hay lắm... nhưng giá sư phụ cố gắng hoàn thiện thêm nhát nữa bằng cách thêm 1 option cho phép chọn LOẠI cần lấy ra là Latin hay TQ thì càng tuyệt hơn!
Cảm ơn sư phụ trước!
ANH TUẤN
 
Nó nè!
Cấu trúc: ExtrStr(chuỗi, STT nhóm từ, loại)
Loại = 1 : Lấy Latin
Loại = 2 : Lấy thứ khác

To Anhtuan: Làm biếng quá đi, sửa có 1 xíu!
 

File đính kèm

Nó nè!
Cấu trúc: ExtrStr(chuỗi, STT nhóm từ, loại)
Loại = 1 : Lấy Latin
Loại = 2 : Lấy thứ khác

To Anhtuan: Làm biếng quá đi, sửa có 1 xíu!
Gọi là làm tùy theo sức của mình... Phân công rõ ràng, ai sở trường gì thì làm nấy mà sư phụ.. he... he...
Vậy là OK, đệ sẽ chỉ đường link cho các đồng chí bên ddth.com qua đây xem sư phụ biểu diển...
ANH TUẤN
 
lâu quá không post nên post đại vài câu!
Đừng post đại chứ, lâu không post thì làm thiệt đi!
1.- Dồn 3 cái thành 1
2.- Thay Select case thành If then

Câu 2 dễ, câu 1 Thunghi làm được mà ngắn, đơn giản, dễ hiểu như vậy mới tài!
Đùa tí, nhưng quan điểm mình là làm vậy nó rõ ràng, dễ hiểu hơn, dù mình làm chưa phải tối ưu.
 
Gộp "3 TRONG 1" cho VUI

Đừng post đại chứ, lâu không post thì làm thiệt đi!
1.- Dồn 3 cái thành 1
2.- Thay Select case thành If then

Câu 2 dễ, câu 1 Thunghi làm được mà ngắn, đơn giản, dễ hiểu như vậy mới tài!
Đùa tí, nhưng quan điểm mình là làm vậy nó rõ ràng, dễ hiểu hơn, dù mình làm chưa phải tối ưu.

Gộp "3 TRONG 1" cho VUI

PHP:
Function ExtrStr2(Mystr As String, sttchuoi As Byte, Loai As Byte) As String
Dim Kqtam As String, kQ As String, Lenst As Byte, newStr2 As String
newStr2 = Mystr
For j = 1 To sttchuoi
  If Len(newStr2) = 0 Then
        ExtrStr2 = "": Exit Function
  Else
  Kqtam = ""
  Lenst = Len(newStr2)
  For i = 1 To Lenst
    tam = Mid(newStr2, i, 1)
    If Loai = 1 Then
      Select Case Asc(tam)
        Case 32, 65 To 90, 97 To 122
            Kqtam = Kqtam & tam
            If i <= Lenst - 1 Then
                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 Select
    Else
      If Asc(tam) = 63 Then
            Kqtam = Kqtam & tam
            If i <= Lenst - 1 Then
                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
    End If
  Next i
  kQ = Kqtam
  End If
Next j
ExtrStr2 = kQ
End Function
Như thế này cho hấp dẫn hơn a ptm0412 ah, Nhìn cho rõ thuật toán hơn hix hix@#!^%
Thử sức tí cho vui đó mà,
Đúng là thuật toán chưa tối ưu vì mất công dò tìm từ đầu đến cuối chuỗi (và lại còn dò từ ký tự nữa) - TUY vậy chuỗi bất kỳ kiểu này chắc k có ít cách nào hay hơn
 
Lần chỉnh sửa cuối:
Gọi là làm tùy theo sức của mình... Phân công rõ ràng, ai sở trường gì thì làm nấy mà sư phụ.. he... he...
Vậy là OK, đệ sẽ chỉ đường link cho các đồng chí bên ddth.com qua đây xem sư phụ biểu diển...
ANH TUẤN

Hồi này a tuấn định sang đá sân khách ah,

kẻo này không đá - lại kéo về sân Nhà đá đây....
.
 
Vui thật!
Nhưng TigerTiger chỉ đổi 1 Select case thành if thôi à? Cái kia để nguyên dễ hơn à?
Sao không:
Select Case Asc(tam)
Case 32, 65 To 90, 97 To 122

đổi thành:

If Asc(tam) <> 63

Ban đầu mình sợ Asc() trả về các giá trị khác nhau cho các ký tự Miên khác nhau (>255) nên mới làm thế. Sau biết rằng mọi ký tự Miên đều cho giá trị 63, thì làm biếng sửa thành if. :)
 
Ver3 (ExtrStr3) cho hoành tráng lun

Vui thật!
Nhưng TigerTiger chỉ đổi 1 Select case thành if thôi à? Cái kia để nguyên dễ hơn à?
Sao không:
Select Case Asc(tam)
Case 32, 65 To 90, 97 To 122

đổi thành:

If Asc(tam) <> 63

Ban đầu mình sợ Asc() trả về các giá trị khác nhau cho các ký tự Miên khác nhau (>255) nên mới làm thế. Sau biết rằng mọi ký tự Miên đều cho giá trị 63, thì làm biếng sửa thành if. :)

Oh, thế thì k để ý a ptm ah,
Sửa lun thành Ver3 (ExtrStr3) cho hoành tráng lun thế này

PHP:
Function ExtrStr3(Mystr As String, sttchuoi As Byte, Loai As Byte) As String
Dim Kqtam As String, kQ As String, Lenst As Byte, 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
            If i <= Lenst - 1 Then
                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
            If i <= Lenst - 1 Then
                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
 
Lần chỉnh sửa cuối:
TUY vậy chuỗi bất kỳ kiểu này chắc k có ít cách nào hay hơn
Hic! Không có ít cách hay hơn, tức là nhiều cách hay hơn!
Nhưng an ủi 1 điều:
Đúng là thuật toán chưa tối ưu vì mất công dò tìm từ đầu đến cuối chuỗi (và lại còn dò từ ký tự nữa)
Có 1 cái Exit for, nên không tìm đến cuối chuỗi, trừ khi tách nhóm từ cuối cùng.
Dù gì len(MyStr) chắc cũng không quá 100, For chạy tối đa 100 lần, chắc tối đa 1/100 giây :)

PS: Nếu từ đầu nhìn code Ver 3.0 chắc mù tịt, vì những if là if 4, 5 cái lồng nhau. Và lồng đôi!
Mình vẫn chịu cách để rời 3 cái hơn.
 
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

Để ý 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.
 
Các bạn kiểm tra lại, nếu cho ví dụ như thế này thì sai:
马来 西亚New Zealand 隆坡Kuala Lumpur
Có khoảng trắng trong chuỗi latin thì hàm tách đúng (New Zealand/Kuala Lumpur) nhưng khoảng trắng trong chuỗi không phải latin tách sai (马来/西亚//隆坡).
Nếu chấp nhận "New Zealand" là 1 nhóm thì "马来 西亚" cũng phải là 1 nhóm.
 
Thanks Mr. Long,
Khoảng trắng giữa các ký tự Hoa mình cũng nghĩ tới, nhưng lúc đó mình cho rằng chữ Hoa không có xài khoảng trắng. (nghĩ vậy chắc sai)
Vậy mình sửa lại code bài #12 và dự phòng luôn 2 khoảng trắng trở lên.
Nếu dự phòng luôn dấu chấm, dấu phẩy nữa thì thua! Chắc không có đâu ha!
 

File đính kèm

Thanks Mr. Long,
Khoảng trắng giữa các ký tự Hoa mình cũng nghĩ tới, nhưng lúc đó mình cho rằng chữ Hoa không có xài khoảng trắng. (nghĩ vậy chắc sai)
Vậy mình sửa lại code bài #12 và dự phòng luôn 2 khoảng trắng trở lên.
Nếu dự phòng luôn dấu chấm, dấu phẩy nữa thì thua! Chắc không có đâu ha!

Không biết tiếng Hoa có dấu cách không, nhưng nếu có dấu cách mình nghĩ là nó liên tục.
Còn vấn đề này cần bàn tiếp, tại anhtuan đưa ví dụ gồm latin và Hoa nên các bạn nghĩ là các hàm này tách latin và Hoa. Thật ra nó chỉ tách 2 nhóm:
- Nhóm code <256 (trong nhóm này cũng có nhiều ký tự miên)
- Nhóm code >=256.
Ví dụ chuỗi 马来¥§¢ÆğĘĒﻉﻼﮖۻۺҗ西亚Malaysia吉隆坡 Excel và việc Xử lý dữ liệu
Kết quả sau khi tách:
Nhóm <256: ¥§¢ÆğĘĒ / / Malaysia / Excel và vi / c X / lý d / li / u
Nhóm >=256: 马来 / ﻉﻼﮖۻۺҗ西亚 / 吉隆坡 / / /
 
Không biết tiếng Hoa có dấu cách không, nhưng nếu có dấu cách mình nghĩ là nó liên tục.
Còn vấn đề này cần bàn tiếp, tại anhtuan đưa ví dụ gồm latin và Hoa nên các bạn nghĩ là các hàm này tách latin và Hoa. Thật ra nó chỉ tách 2 nhóm:
- Nhóm code <256 (trong nhóm này cũng có nhiều ký tự miên)
- Nhóm code >=256.
Ví dụ chuỗi 马来¥§¢ÆğĘĒﻉﻼﮖۻۺҗ西亚Malaysia吉隆坡 Excel và việc Xử lý dữ liệu
Kết quả sau khi tách:
Nhóm <256: ¥§¢ÆğĘĒ / / Malaysia / Excel và vi / c X / lý d / li / u
Nhóm >=256: 马来 / ﻉﻼﮖۻۺҗ西亚 / 吉隆坡 / / /


Oh, thế này là phức tạp vấn đề rùi
Liệu có bài toán thực tế không nhỉ
Nếu có như thế -> chúng ta phải có bảng mã của tất cả các ký tự đã có mặt trong bảng mã UNICOE của các ký tự của các ngôn ngữ đó -> phân loại được
hix:-=
 
Dùng tạm mấy hàm này cho chữ Hoa và chữ Anh theo yêu cầu bài #1 cái đã. Sau này gạp dữ liệu thực chữ Thái, chữ Ả rập ... thì tính sau. Chuyện này để phiền Anh Long nhắc mấy lần trong mấy bài liền, ngại quá.

1- Nếu 2 ngôn ngữ la tinh, trong đó kể luôn tiếng Việt có dấu, đó là vấn đề sắp xếp dữ liệu, tránh để tình trạng gộp lại rồi phải tách ra.
2- Nếu may chỉ 1 ngôn ngữ tượng hình + 1 ngôn ngữ Latinh , Dùng hàm này hoặc điều chỉnh lại cho những ngôn ngữ mà mã ASCII nửa dưới 256, nửa trên 256.(trong đó có tiếng Việt)
Chắc ở Việt nam chẳng có trường hợp dữ liệu có cả 2 ngôn ngữ đều tượng hình, hay 1 lúc 3, 4 ngôn ngữ như Bác Duy Long cảnh báo đâu.
Mà nếu có thì trở lại điều 1
 
Chắc ở Việt nam chẳng có trường hợp dữ liệu có cả 2 ngôn ngữ đều tượng hình, hay 1 lúc 3, 4 ngôn ngữ như Bác Duy Long cảnh báo đâu.
Mà nếu có thì trở lại điều 1

Yes, thế là đủ dùng, mà tác giả hỏi bài này (bên sân khách) chắc cũng chưa thăm chủ đề này rùi,

Đợi người hỏi vậy đã, biết đâu lại nảy sinh vấn đề khác...(???)
 
Yes, Đợi người hỏi vậy đã, biết đâu lại nảy sinh vấn đề khác...(???)
Cũng may mới là tên nước; nếu trong chuỗi la tin & tiếng hoa này mà có vài ký số biểu thị địa chỉ số nhà nữa chắc toi luôn!!!
 
Tôi nói lại lần nữa về bài toán này:
1> Chỉ có 2 ngôn ngữ là ANH và HOA (chắc chắn)
2> Trong phần tiếng HOA có khoảng trắng hay ko thì chưa chắc
Chỉ vậy thôi....
ANH TUẤN
 
Khoảng trắng thì xử rồi Anhtuan à. Còn ký tự số xen lẫn vào thì dùng linh hoạt 1 chút là được, không sửa code. Xem file thí dụ.
 

File đính kèm

Khoảng trắng thì xử rồi Anhtuan à. Còn ký tự số xen lẫn vào thì dùng linh hoạt 1 chút là được, không sửa code. Xem file thí dụ.
Ai chà... hay nhỉ? Tuy nhiên yêu cầu tác giã ko cao đến mức đó đâu... Trong chuổi chỉ có chử, ko số siết hay ký tự đặc biệt gì ráo trọi...
Như vầy là ngon lành lắm rồi...
Cảm ơn sư phụ
 
Liệu có thể thêm code đếm trong chuỗi có bao nhiêu chuỗi con mỗi loại và dùng phép nối để chỉ cần công thức tách

thì hay biết bao cho người sử dụng​


Bạn xem thử thủ tục của mình ở bài trước. Có thể giải quyết được. Chỉ cần thêm giá trị thứ tự chuỗi con vào sau dấu cách (Biến Signal).
 
Bạn Boyxin ơi! không biết đoạn code này viết có giống ý bạn không? Mình cũng mạo muội gửi lên đâu, code này giống như file mình gửi bài trước nhưng chỉnh lại một tí cho gọn hơn và thêm yêu cầu điển số thự tự nhóm.

PHP:
Function TachChu(TargetText As String, TextType As String, Optional Signal As String)
Dim ResultText As String
Dim TextLenth, ZZ, Ordinal As String
Dim ZPoint(1000, 1) As Variant
IZ = -1
Ordinal = "2"
TextLenth = Len(TargetText) 'Dem so ky tu trong chuoi
If TextLenth = 0 Then
        TachChu = "": Exit Function
Else
        If TextType = 0 Then        'Quet ky tu ABC
            'Quet cac ky tu tu trai qua phai, ky tu nao la dang ABC thi cho vao bang luu
            For ZZ = 1 To TextLenth
                    If Asc((Mid(TargetText, ZZ, 1))) <> 63 Then
                         ResultText = ResultText + Mid(TargetText, ZZ, 1)
                         IZ = IZ + 1
                         ZPoint(IZ, 0) = ZZ
                         ZPoint(IZ, 1) = Mid(TargetText, ZZ, 1)
                    End If
            Next ZZ
        Else
        ' Quet cac ky tu tu trai qua phai, ky tu nao khong phai la dang ABC thi cho vao bang luu:
            For ZZ = 1 To TextLenth
                    If Asc((Mid(TargetText, ZZ, 1))) = 63 Then
                        ResultText = ResultText + Mid(TargetText, ZZ, 1)
                        IZ = IZ + 1
                        ZPoint(IZ, 0) = ZZ
                        ZPoint(IZ, 1) = Mid(TargetText, ZZ, 1)
                    End If
            Next ZZ
        End If
'=================================================
            'Gan gia tri tim duoc dau tien vao ket qua
        ResultText = ZPoint(0, 1)
            For JZ = 1 To IZ
                If ZPoint(JZ, 0) - ZPoint(JZ - 1, 0) = 1 Then
                    ResultText = ResultText + ZPoint(JZ, 1)
                Else
                    ResultText = ResultText + Signal + Ordinal + "-" + ZPoint(JZ, 1)
                    Ordinal = Ordinal + 1
                End If
            Next JZ
End If
TachChu = ResultText
End Function
 
Hàm của ca_dafi cho kết quả tốt, tuy nhiên phải chạy đến 3 vòng lặp. Mình viết kết hợp chỉ chạy 1 vòng, các bạn xem và cho ý kiến:
Mã:
Option Explicit
Function TachChu(TargetText As String, TextType As Byte)
Dim ResultText1 As String, ResultText2 As String
Dim ResultLT As String, ResultTQ As String, Result1 As String, Result2 As String, StrC As String
Dim TextLenth As Integer, i As Integer, j As Integer, k As Integer
Dim iCode As Byte
On Error GoTo ketthuc
    TextLenth = Len(TargetText)
For i = 1 To TextLenth + 1
  iCode = Asc((Mid(TargetText, i, 1)))
  StrC = Mid(TargetText, i, 1)
     If iCode <> 63 Then
       Result2 = LTrim(Result2)
       ResultTQ = Left(Result2, k)
         If ResultTQ <> ResultText2 Then Result2 = Result2 & " " & ResultText2
       k = 0
       ResultText2 = ""
             ResultText1 = ResultText1 & StrC
             j = j + 1
    Else
      Result1 = LTrim(Result1)
      ResultLT = Left(Result1, j)
         If ResultLT <> ResultText1 Then Result1 = Result1 & " " & ResultText1
      j = 0
      ResultText1 = ""
             ResultText2 = ResultText2 & StrC
             k = k + 1
    End If
Next
ketthuc:
 If TextType = 0 Then TachChu = Result1 & " " & ResultText1
 If TextType = 1 Then TachChu = Result2 & " " & ResultText2
End Function
 

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

Back
Top Bottom