Nhờ các bạn/Anh/Chị sửa vòng lặp For và lệnh Mid (1 người xem)

Liên hệ QC

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

thinh.cao

Thành viên mới
Tham gia
30/3/09
Bài viết
27
Được thích
9
Mình tìm cả ngày mà chẳng biết lỗi phát sinh ở đâu. Nhờ mọi người giúp. Xin cảm ơn nhiều.

Sub Macro3()
Dim dc_open As Double
Dim xoa_sum As Double
Dim i, n As Double

xoa_sum = Sheets("13100010").Range("Q10000").End(xlUp).Row
dc_open = Sheets("13100010").Range("O10000").End(xlUp).Row



For i = 9 To dc_open

n = Application.WorksheetFunction.Mid(Range(Cells(i, 15)), 1, 2) & "/" & _
Application.WorksheetFunction.Mid(Range(Cells(i, 15)), 4, 2) & "/" & _
Application.WorksheetFunction.Mid(Range(Cells(i, 15)), 7, 4)

Range(Cells(i, 15)) = n
Next
.....

End sub
 

File đính kèm

Đoạn vòng lặp for của bạn mình hiểu ý là chuyển giá trị text thành giá trị ngày tháng năm. Có 2 cách
Cách 1:
PHP:
for i = 9 to dc_open
Cells(i, 15).Value = DateSerial(Right(Cells(i, 15).Value, 4), Mid(Cells(i, 15).Value, 4, 2), Left(Cells(i, 15).Value, 2))
Next
Cách 2:
PHP:
for i = 9 to dc_open
Cells(i, 15).Value = Replace(Cells(i, 15).Value, ".", "/")
Next
 
Upvote 0
Đoạn vòng lặp for của bạn mình hiểu ý là chuyển giá trị text thành giá trị ngày tháng năm. Có 2 cách
Cách 1:
PHP:
for i = 9 to dc_open
Cells(i, 15).Value = DateSerial(Right(Cells(i, 15).Value, 4), Mid(Cells(i, 15).Value, 4, 2), Left(Cells(i, 15).Value, 2))
Next
Cách 2:
PHP:
for i = 9 to dc_open
Cells(i, 15).Value = Replace(Cells(i, 15).Value, ".", "/")
Next
Cách 1: ĐÚNG
Cách 2: TRẬT LẤT
Bạn tự suy nghĩ xem tại sao lại TRẬT LẤT nhé
---------------------
Mình tìm cả ngày mà chẳng biết lỗi phát sinh ở đâu. Nhờ mọi người giúp. Xin cảm ơn nhiều.

Sub Macro3()


n = Application.WorksheetFunction.Mid(Range(Cells(i, 15)), 1, 2) & "/" & _
Application.WorksheetFunction.Mid(Range(Cells(i, 15)), 4, 2) & "/" & _
Application.WorksheetFunction.Mid(Range(Cells(i, 15)), 7, 4)

End sub
Cái màu đỏ đỏ là bạn tự CHẾ ra à? (trong VBA làm đếch gì có cái này)
 
Upvote 0
Cách 1: ĐÚNG
Cách 2: TRẬT LẤT
Bạn tự suy nghĩ xem tại sao lại TRẬT LẤT nhé
---------------------

Cái màu đỏ đỏ là bạn tự CHẾ ra à? (trong VBA làm đếch gì có cái này)
Theo em sẽ sai nếu định dạng ngày tháng năm không chọn ký tự "/" làm dấu phân cách.
 
Upvote 0
Cách 1: ĐÚNG
Cách 2: TRẬT LẤT
Bạn tự suy nghĩ xem tại sao lại TRẬT LẤT nhé
---------------------

Cái màu đỏ đỏ là bạn tự CHẾ ra à? (trong VBA làm đếch gì có cái này)
Cái màu đỏ đấy có chứ không phải "đếch có" đâu nhé, chẳng qua là bạn không biết thôi. VBA rất rộng bạn xem EXP trong files đính kèm nhé (hướng dẫn từ giảng viên đại học KHTN HCM).

Dù sao cũng cảm ơn bạn đã góp ý.
 

File đính kèm

Upvote 0
Theo em sẽ sai nếu định dạng ngày tháng năm không chọn ký tự "/" làm dấu phân cách.

Hỏng phải vậy!
Sẽ ĐÚNG hoặc SAI tùy vào thiết lập trong Control Panel (của Windows)
Nó sai và nhìn thấy nó sai còn đở (do nhìn thấy nó định dạng Text.
Tình huống vầy mới chết nè: chuổi 10.05.2013 sau khi Replace dấu chấm thành dấu "/" xong sẽ có 2 kết quả khác nhau tùy thuộc vào Control Panel
ngày 10 tháng 5 nếu control panel thiết lập dd/MM/yy
ngày 5 tháng 10 nếu control panel thiết lập MM/dd/yy
===> Sai cả mấy km luôn
 
Upvote 0
Cái màu đỏ đấy có chứ không phải "đếch có" đâu nhé, chẳng qua là bạn không biết thôi. VBA rất rộng bạn xem EXP trong files đính kèm nhé (hướng dẫn từ giảng viên đại học KHTN HCM).

Dù sao cũng cảm ơn bạn đã góp ý.
Đúng là thế, nhưng tội gì phải khổ cực với đoạn code dài ngoằng thế hả bạn! Hàm mid() có cả trong Excel và VBA, đang viết code thì dùng hàm trong VBA đi cho lành!!
 
Upvote 0
Cách 2: TRẬT LẤT
Lý do: Bị nhảy định dạng ngày tháng.

Cảm ơn bạn vì cách 1, cảm ơn rất nhiều.
 
Upvote 0
Hỏng phải vậy!
Sẽ ĐÚNG hoặc SAI tùy vào thiết lập trong Control Panel (của Windows)
Nó sai và nhìn thấy nó sai còn đở (do nhìn thấy nó định dạng Text.
Tình huống vầy mới chết nè: chuổi 10.05.2013 sau khi Replace dấu chấm thành dấu "/" xong sẽ có 2 kết quả khác nhau tùy thuộc vào Control Panel
ngày 10 tháng 5 nếu control panel thiết lập dd/MM/yy
ngày 5 tháng 10 nếu control panel thiết lập MM/dd/yy
===> Sai cả mấy km luôn
Ah, vâng, em thừa nhận sai!! Em cứ nghĩ người khác cũng dùng thiết lập chuẩn VN như em vẫn dùng!!
 
Upvote 0
Cái màu đỏ đấy có chứ không phải "đếch có" đâu nhé, chẳng qua là bạn không biết thôi. VBA rất rộng bạn xem EXP trong files đính kèm nhé (hướng dẫn từ giảng viên đại học KHTN HCM).

Dù sao cũng cảm ơn bạn đã góp ý.

Thế bạn bảo tôi XEM CÁI GÌ trong này? là cái Application.WorksheetFunction.CountA à?
Nếu đúng thế thì tôi nói bạn CHẾ là đúng rồi còn gì
Thấy WorksheetFunction.CountA là để đếm, thế là bạn suy ra WorksheetFunction.Mid để xử lý chuổi? Tôi nói đúng chứ?
Tóm lại: VBA đếch có cái gì gọi là WorksheetFunction.Mid cả
 
Upvote 0
Thôi được rồi, bạn đúng, tôi sai. cảm ơn các bạn vì đã góp ý. chúc một ngày đầu tuần vui vẻ.

Thân,
Đức Thịnh
 
Upvote 0
Upvote 0
Đoạn vòng lặp for của bạn mình hiểu ý là chuyển giá trị text thành giá trị ngày tháng năm. Có 2 cách
Cách 1:
PHP:
for i = 9 to dc_open
Cells(i, 15).Value = DateSerial(Right(Cells(i, 15).Value, 4), Mid(Cells(i, 15).Value, 4, 2), Left(Cells(i, 15).Value, 2))
Next
Cách 2:
PHP:
for i = 9 to dc_open
Cells(i, 15).Value = Replace(Cells(i, 15).Value, ".", "/")
Next
Vẫn không chạy, Bạn có thể gửi files lên lại giúp mình không.
Một lần nữa, xin cảm ơn.
 
Upvote 0
Mình thừa nhận rồi mà, Đôi lúc mình cũng hơi máy móc.
 
Upvote 0
@thinh.cao:
Theo luật chung của VBA Excel:
- những hàm nào trong VBA in hệt như worksheeet thì hàm VBA sẽ che hàm worksheet. Điển hình là hàm MID
- những hàm nào trong VBA không hoàn toàn giống với worksheet thì tuỳ theo kết quả cần lấy mà người dùng có quyền chọn lựa.
Ví dụ với hàm ROUND cách làm tròn của VBA khác với worksheet và người dùng phải biết cách chọn (thử Round(5.65,1) cho hàm VBA và hàm worksheet sẽ thấy chúng cho kết quả khác nhau)

Về code của bạn thì biểu thức này có hai lỗi:
Application.WorksheetFunction.Mid(Range(Cells(i, 15)), 1, 2)
1. hàm mid của worksheet không gọi được
2. Hàm Range nhận tham là địa chỉ của Cells chứ không phải cells cho nên bạn phải thêm thuộc tính Address
Sửa lại: Mid(Range(Cells(i, 15).Address), 1, 2)

Tuy nhiên, tôi nghĩ trong bài tập này bạn hiểu lầm mục đích ví dụ xử lý MID

Đối với VBA, string có tính bất biến (immutable) cho nên mỗi lần cộng trừ, VBA phải lập một chuỗi mới, copy trị qua và bỏ chuõi cũ.
Để có hiệu quả hơn, khi cần thay đổi một vài ký tự ở vị trí nhất định trong chuõi, dùng hàm MID trực tiếp sẽ có hiệu suất cao hơn.

Trường hợp của bạn cần thay dấu chấm ở vị trí 3 và 6 thành dấu chéo, chỉ cần viết:
MID( chuỗi, 3, 1 ) = "/"
MID( chuỗi, 6, 1 ) = "/"
VBA sẽ trực tiếp thay ký tự trên chuỗi, không cần phải lập chuỗi mới. Đó là một tính chất đặc thù của hàm MID.
 
Lần chỉnh sửa cuối:
Upvote 0
Bạn dũng cảm nhận lỗi nên mình thêm cho bạn 1 cách :

for i = 9 to dc_open
Cells
(i, 15)= CDate(Cells(i, 15))
Next

Cái này cũng có thể sai y chang như em đã nói ở bài 6
------------------------------------------------------------------
Trường hợp của bạn cần thay dấu chấm ở vị trí 3 và 6 thành dấu chéo, chỉ cần viết:
MID( chuỗi, 3, 1 ) = "/"
MID( chuỗi, 6, 1 ) = "/"
VBA sẽ trực tiếp thay ký tự trên chuỗi, không cần phải lập chuỗi mới. Đó là một tính chất đặc thù của hàm MID.

Mình thí nghiệm thấy LÀM GÌ CÓ VỤ NÀY đâu ta?
Với đoạn code MID( chuỗi, 3, 1 ) = "/" thì VBA sẽ hiểu là SO SÁNH 2 CHUỔI (kết quả trả về là TRUE hoặc FALSE) chứ chẳng thay thế được cái gì cả
 
Lần chỉnh sửa cuối:
Upvote 0
Cái này cũng có thể sai y chang như em đã nói ở bài 6
------------------------------------------------------------------


Mình thí nghiệm thấy LÀM GÌ CÓ VỤ NÀY đâu ta?
Với đoạn code MID( chuỗi, 3, 1 ) = "/" thì VBA sẽ hiểu là SO SÁNH 2 CHUỔI (kết quả trả về là TRUE hoặc FALSE) chứ chẳng thay thế được cái gì cả


Chào mọi người,

Xin thông báo là code đã chạy và đúng. Cảm ơn tất cả.
 
Upvote 0
Vẫn không chạy, Bạn có thể gửi files lên lại giúp mình không.
Một lần nữa, xin cảm ơn.

Viết cho bạn luôn 1 Tool để làm "đồ chơi"
Mã:
Private Sub Text2Date(ByVal Table As Range)
  Dim aTable, tmp As String
  Dim lR As Long, lC As Long, lDate As Long
  On Error Resume Next
  aTable = Table.Value
  If Table.Count = 1 Then
    ReDim aTable(1, 1): aTable(1, 1) = Table
  End If
  For lR = 1 To UBound(aTable, 1)
    For lC = 1 To UBound(aTable, 2)
      tmp = CStr(aTable(lR, lC))
      If Len(tmp) Then
        If tmp Like "##.##.####" Then
          lDate = DateSerial(Right(tmp, 4), Mid(tmp, 4, 2), Left(tmp, 2))
          aTable(lR, lC) = lDate
        End If
      End If
    Next
  Next
  Table.Value = IIf(Table.Count = 1, aTable(1, 1), aTable)
End Sub
Ở trên là "đồ chơi", Bạn hiểu cũng được mà không hiểu cũng không sao, chỉ cần biết áp dùng
Đây là code để áp dụng:
Mã:
Sub Main()
  Dim Table As Range
  With Sheets("13100010").Range("O9:O1000")
    .NumberFormat = "dd/MM/yyyy"
    Text2Date .Cells
  End With
End Sub
Tất cả code trên cho vào 1 Module
Sub Main sẽ covert các chuổi trong vùng O9:O1000 thành Date
Còn món "đồ chơi" ở trên (Sub Text2Date) có thể dùng sau này vào công việc tương tự (cho file khác hoặc sheet khác, vùng dữ liệu tùy ý)
----------------
Chào mọi người,

Xin thông báo là code đã chạy và đúng. Cảm ơn tất cả.
Chạy đúng là MAY MẮN thôi... Không có nghĩa là mang sang máy tính khác code cũng sẽ đúng
(Bạn tin hay không thì tùy)
 

File đính kèm

Upvote 0
Cảm ơn ndu96081631 nhé. Những gì bạn vừa nói mình hiểu 30%. Hiểu được cái Sub main () thôi.
Ứng dụng VBA vào công việc rất hay nhưng đôi khi sai một ly đi 100 km. Mình không am hiểu lập trình lắm nhưng chỉ cần có công cụ thì có thể thử và sử dụng.
Ah, bạn có nhớ, bạn đã từng......lock !$@!!
 
Upvote 0
Chuyện kể rằng ngày xửa ngày xưa có một người viết bài nhờ sửa files với tiêu đề không cụ thể, thế là bị....khóa.
Để rồi người đó ấm ức mất 15... phút.

http://www.giaiphapexcel.com/forum/...àn-thiện-files&p=524585&highlight=#post524585
Nếu bạn vẫn "ấm ức" thì với tư cách cá nhân mình có thể xin lỗi bạn!
Nhưng với tư cách là mod của diễn đàn, mình đành phải làm vậy thôi
Ẹc... Ẹc... Bạn cũng đã nói đó là chuyện ngày xửa ngày xưa, vậy thì bây giờ bạn chú ý một chút về cách đặt tiêu đề là được rồi
(mình cũng chả nhớ nỗi chuyện ngày xửa ngày xưa ấy nữa)
 
Upvote 0
Cái này cũng có thể sai y chang như em đã nói ở bài 6
------------------------------------------------------------------


Mình thí nghiệm thấy LÀM GÌ CÓ VỤ NÀY đâu ta?
Với đoạn code MID( chuỗi, 3, 1 ) = "/" thì VBA sẽ hiểu là SO SÁNH 2 CHUỔI (kết quả trả về là TRUE hoặc FALSE) chứ chẳng thay thế được cái gì cả

Chắc chắn thay.
Mà thôi ta xét cái khác.

Mid(chuoi, 3, 1) = "/" của VetMini không thể là biểu thức lô gíc được. Biểu thức lô gíc thì hoặc
1. Giá trị của nó phải được gán cho biến nào đó (hoặc là một kết quả trung gian trong tính toán)

Mã:
Dim a
a [SIZE=6][B][COLOR=#ff0000]=[/COLOR][/B][/SIZE] Mid(chuoi, 3, 1) = "/"
...

hoặc

2. là biểu thức lô gíc - đk trong những "vị trí" đòi hỏi giá trị lô gíc, vd. IF ..., Do While ..., Do ... Loop While ...

Không có chuyện biểu thức lô gíc đứng "chơ vơ, một mình" cả.

Tương tự ta có (1 + 2) * 3 là biểu thức số học. Giá trị đó có thể gán cho 1 biến nào đó, vd.
Mã:
a [SIZE=6][COLOR=#ff0000]=[/COLOR][/SIZE] (1 + 2) * 3

Làm gì có câu lệnh nào mà biểu thức đó đứng "chơ vơ" được.
Mã:
    chuoi = "he he"
    [COLOR=#ff0000](1 + 2) * 3[/COLOR]

Làm sao viết dòng đỏ đỏ được?
--------------
Nếu là Mid(chuoi, 3, 1) <> "/" thì đây đúng là biểu thức lô gíc vì ta có "<>"
Nhưng đã là biểu thức thì không thể đứng chơ vơ được. Tức
Mã:
    chuoi = "he he"
    [COLOR=#ff0000]Mid(chuoi, 3, 1) <> "/"[/COLOR]

Dòng đỏ đỏ không "qua được"

Tóm lại
1. Mid(chuoi, 3, 1) <> "/" không đứng "chơ vơ" được vì nó là biểu thức (lô gíc)
2. Mid(chuoi, 3, 1) = "/" đứng "chơ vơ" được vì nó không là biểu thức (lô gíc)
--------------

Tất nhiên VBA hay compilator trong các ngôn ngữ khác rất thông minh

Mã:
dim a as long, b as long

[B][COLOR=#ff0000]a = b[/COLOR][/B]    'gán giá trị b cho a
.....

IF [B][COLOR=#0000ff]a = b[/COLOR][/B] then

chúng hiểu ngay là a = b không là biểu thức, còn a = b là biểu thức lô gíc
 
Lần chỉnh sửa cuối:
Upvote 0
string (chuỗi) được hệ thống phát cho một vùng trong bộ nhớ với độ dài nhất định.
Khi làm toán thay đổi chuỗi, VBA bắt buộc phải phát cho chuỗi một vùng nhớ khác bởi vì nó không biết chuỗi mới có dài bằng chuỗi cũ hay không - nếu dài quá thì xâm phạm qua vùng nhớ của biến khác sao!

Vì vây làm con toán
a = left(a,2) & "/" & mid(a,4,len(a)-3)
trên nguyên tắc là chỉ muốn đổi trị của ký tự thứ 3 trong chuỗi, nhung thực tế ra rất tốn kém vì hệ thống phải liên tục thay đổi vùng nhớ của chuỗi.

Để giúp người dùng làm việc hiệu quả hơn, VBA có cho phép dùng hàm MID một cách đặc biệt như thế. Với cách truy cứu trực tiếp, chuỗi không bị đổi, chỉ trị ký tự trong chuỗi bị đổi thôi.

Thật ra các phiên bản cũ của BASIC còn cung cấp một số hàm làm việc với chuỗi mà không thay đổi vùng nhớ. Nhưng hình như qua đến VB thì các hàm này bị bỏ hết.

=== 04/09/2013 : 10:02am bổ xung code chứng minh ===

Chạy thử đoạn code này (trong immediate window)
s = "12345": ? s & " truoc khi doi" : mid(s,3,2) = "cd" : ? s & " sau khi doi"

Se thấy in ra
12345 truoc khi doi
12cd5 sau khi doi
 
Lần chỉnh sửa cuối:
Upvote 0

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

Back
Top Bottom