Board logo

標題: [發問] 同一儲存格內資料進行大小比對 [打印本頁]

作者: ranceymm    時間: 2022-12-12 17:32     標題: 同一儲存格內資料進行大小比對

各位大大

想請問一下,
如圖:資料在D行,有辦法用函數在B行顯示出D行"長"後面最大的數值嗎?

[attach]35593[/attach]

[attach]35594[/attach]

有試過MID+FIND,不過公式會很長,
SUBSTITUE也沒辦法支援萬用字元,所以無法將"長"前面的字元取代掉...
作者: 准提部林    時間: 2022-12-12 21:31

C3/
陣列公式(三鍵齊按)//
=MAX(--TEXT(SUBSTITUTE(MID(SUBSTITUTE(SUBSTITUTE(D3,"長","、長"),"、",REPT(" ",99)&"|"),ROW($1:$19)*99-98,99),"|長",),"G/通用格式;0;0;\0"))

若文字太長, 就用VBA吧!
作者: ranceymm    時間: 2022-12-12 22:39

回復 2# 准提部林


感謝大神幫忙,想不到苦惱了兩個星期的函數可以這樣寫。
這樣可以求出需要的值,若資料更多筆只要ROW那邊把列數增加就可以對應了。

  用MID跟FIND土法煉鋼可能要寫個十幾行的公式...
作者: hcm19522    時間: 2022-12-13 10:54

https://blog.xuite.net/hcm19522/twblog/590654094
作者: Andy2483    時間: 2022-12-13 13:45

本帖最後由 Andy2483 於 2022-12-13 13:48 編輯

回復 1# ranceymm


    謝謝前輩發表此主題與範例
自定義函數方式供參考
後學藉此帖練習陣列與字典,自定義函數()

使用方法:
1.將下列程式碼放入Module1
2.[B3]儲存格輸入"=最大值("長","、",D3)"
[attach]35596[/attach]

Option Explicit
Function 最大值(前字元 As String, 後字元 As String, 儲存格 As Range) As Double
Dim Y, A$, j&, P#, V
Application.Volatile
Set Y = CreateObject("Scripting.Dictionary")
   A = Replace(Replace(Replace(儲存格, " " & 前字元, ","), 後字元, ","), " ", ",")
   V = Split(A, ",")
   For j = 3 To UBound(V) Step 4
      If IsNumeric(V(j)) And V(j) <> "" Then
         P = V(j): Y(P) = ""
      End If
   Next
   最大值 = Application.Max(Y.keys())
End Function
作者: ranceymm    時間: 2022-12-13 22:54

回復 4# hcm19522


    感謝hcm大提供這麼多種方法,
    前兩個函數寫法在資料筆數出現第8個時就會出現錯誤,小的功力不足,看不出是哪邊的問題...
   
    第三個函數是逐字比對,然後再抓取數字取MAX嗎?
    沒想過LARGE跟SMALL能這樣用,這個寫法在其他資料比對還滿萬用的呢!
作者: ranceymm    時間: 2022-12-13 23:11

回復 5# Andy2483


    感謝,VBA是小弟的短項,沒想過用自定義就可以取得想要的數值,這個可以研究一陣子了...
    剛剛測試,無論資料多少筆都可以算出來。
作者: Andy2483    時間: 2022-12-14 07:59

本帖最後由 Andy2483 於 2022-12-14 08:07 編輯

回復 7# ranceymm


    謝謝前輩回復
今天再檢視&複習了此帖,發現很多的多餘與不足,後學也再學習中,先求有,再求好,心得註解供參考

Option Explicit
Function 最大值(前字元 As String, 後字元 As String, 儲存格 As Range) As Double
'↑最大值()是自己定義的函數名字,裡面的:
'前字元 As String :前字元宣告是字串變數,是使用此函數需輸入的值 "長"
'後字元 As String :後字元也宣告是字串變數,是使用此函數需輸入的值 "、"
'儲存格 As Range :儲存格宣告是儲存格變數,而且是使用此函數需輸入(或用選的)的儲存格位址
'As Double是宣告這最大值結果是雙精度小數
'如果要一句話敘述:給這函數兩個字串,一個單格的儲存格位址,後面的程序回傳 雙精度值,
'至於回傳的是不是最大值?? 就要看成是有沒有抓到最大值
'重要的是前輩對資料的邏輯規則是否正確! 資料錯誤就算不出來!有好的開始,成功就不遠了

Dim Y, V, A$, j&, P#
'↑宣告變數:(Y,V)是通用型變數,(A)是字串變數,(j)是長整數變數,(P)是雙精度小數
Application.Volatile
'↑將使用者定義的函數標示為易變。
'https://learn.microsoft.com/zh-tw/office/vba/api/excel.application.volatile
Set Y = CreateObject("Scripting.Dictionary")
'↑令Y是字典
'https://learn.microsoft.com/zh-tw/office/vba/language/reference/user-interface-help/dictionary-object

   A = Replace(Replace(Replace(儲存格, " " & 前字元, ","), 後字元, ","), " ", ",")
   '↑令A這字串變數是 函數使用時輸入 D3 儲存格裡的值,經過三次置換字元 (" 長":",")("、":",")(" ":",")
   'https://learn.microsoft.com/zh-tw/office/vba/language/reference/user-interface-help/replace-function

   V = Split(A, ",")
   '↑令V這通用型變數裝入 A字串被Split()分割成的數個字串,V就變成是一維陣列
   'https://learn.microsoft.com/zh-tw/office/vba/language/reference/user-interface-help/split-function

   For j = 3 To UBound(V) Step 4
   '↑設順迴圈!j從3到V陣列的最後一個索引號碼,j迴圈每繞回來一次就加3,7,11,.....
   'https://learn.microsoft.com/zh-tw/office/vba/language/reference/user-interface-help/fornext-statement

      If IsNumeric(V(j)) And V(j) <> "" Then
      '↑如果索引值j位置的V陣列值經過IsNumeric()函數判斷是數字,而且不是空字元 ??
      'https://learn.microsoft.com/zh-tw/office/vba/language/reference/user-interface-help/isnumeric-function

         P = V(j): Y(P) = ""
         '↑當IF條件成立!就令P這雙精度變數裝入 索引值j位置的V陣列值
         '然後將這P變數當key,item是空字元,倒入Y字典裡

      End If
   Next
   最大值 = Application.Max(Y.keys())
   '↑令 最大值 這雙精度變數用 Max() 取得Y字典裡KEYS的最大值,顯示在儲存格裡
   'https://learn.microsoft.com/zh-tw/office/vba/api/excel.worksheetfunction.max

End Function
作者: Andy2483    時間: 2022-12-14 08:32

本帖最後由 Andy2483 於 2022-12-14 08:43 編輯

回復 6# ranceymm

以前都搞不懂自定義函數,是這帖學來的
http://forum.twbts.com/thread-23804-1-1.html

後學再練習另一種方法供參考
[attach]35597[/attach]

[attach]35598[/attach]

Option Explicit
Function MX(儲存格 As Range) As Double
Dim Y, V, A$, j&, P#
Application.Volatile
Set Y = CreateObject("Scripting.Dictionary")
A = Replace(Replace(Replace(儲存格, " 長", ","), "、", ","), " ", ",")
V = Split(A, ",")
For j = 3 To UBound(V) Step 4
   If IsNumeric(V(j)) And V(j) <> "" Then
      P = V(j): Y(P) = ""
   End If
Next
MX = Application.Max(Y.keys())
Set Y = Nothing : Erase V
End Function

請前輩常上論壇瀏覽,一起學習!
作者: hcm19522    時間: 2022-12-14 09:20

回復 6# ranceymm

公式設定字串長 最多199字  9個數字     第二種 所有199改299 試試
作者: Andy2483    時間: 2022-12-14 13:46

回復 9# Andy2483


    回復自己又測試到更進一步認識 自定義函數
函數裡宣告字串,使用者輸入儲存格位址,會自動轉化為字串值,可以少用一個變數
[attach]35601[/attach]

Option Explicit
Function MXA(字串 As String) As Double
Dim Y, V, j&, P#
Application.Volatile
Set Y = CreateObject("Scripting.Dictionary")
字串 = Replace(Replace(Replace(字串, " 長", ","), "、", ","), " ", ",")
V = Split(字串, ",")
For j = 3 To UBound(V) Step 4
   If IsNumeric(V(j)) And V(j) <> "" Then
      P = V(j): Y(P) = ""
   End If
Next
MXA = Application.Max(Y.keys())
Set Y = Nothing: Erase V
End Function
作者: quickfixer    時間: 2022-12-14 21:36

回復 11# Andy2483

regexp的解法

    Sub test()
    Dim Find_Num, reg As Object, i As Integer, mxa As Double
    Set reg = CreateObject("VBScript.RegExp")
    reg.Pattern = "長(.+?)、"
    reg.Global = True
    Set Find_Num = reg.Execute(Range("d3"))
    If Find_Num.Count > 0 Then
        For i = 0 To Find_Num.Count - 1
            If mxa < Find_Num(i).submatches(0) Then mxa = Find_Num(i).submatches(0)
        Next i
    End If
    MsgBox mxa
    Set reg = Nothing
End Sub
作者: 准提部林    時間: 2022-12-14 22:05

vba自訂函數//
自訂文宇開頭後面的數字
可求 MAX, MIN, SUM...
[attach]35603[/attach]
作者: Andy2483    時間: 2022-12-15 08:30

回復 12# quickfixer


    謝謝前輩指導 正則方法,後學習得很多知識
心得註解如下,請前輩再指導,謝謝

學習執行過程:
[attach]35604[/attach]

學習執行結果:
[attach]35605[/attach]

Option Explicit
Sub test_quickfixer()
Dim Find_Num As Object, reg As Object, i As Integer, mxa As Double
'↑宣告變數!(Find_Num,reg)是通用型變數,(i)是長整數變數,(mxa)是雙精度小數數字
    Set reg = CreateObject("VBScript.RegExp")
    Set Find_Num = CreateObject("VBScript.RegExp")
    '↑令reg這物件變數是 正則
    reg.Pattern = "長(.+?)、"
    '↑令正則的規則是 "長"字元與"、"符號之間(含)
    '會計科目名稱,(.+?)可以是任意字符串故採用.加號表示科目名稱長度不能為0 ,
    '加號之後的問號表示如果與之後的模式衝突時, 盡可能少地匹配相應的字符串(非貪婪匹配)

    reg.Global = True
    '↑正則的結果都要保留
    Set Find_Num = reg.Execute(Range("d3"))
    MsgBox Find_Num(1)
    'MsgBox Find_Num(1, 1) '失敗 偵錯
    'MsgBox Find_Num(1, 0) '失敗 偵錯
    'MsgBox Find_Num(0, 1) '失敗 偵錯

    '↑令Find_Num這通用型變數是 [D3]儲存格值以reg執行的正則
    '之前不確定Find_Num是陣列還是什麼? 今天進一步確定他也是物件
    '1.SET
    '2.Find_Num As Object
    '3.Set Find_Num = CreateObject("VBScript.RegExp")
    '4.MsgBox Find_Num(1)

    If Find_Num.Count > 0 Then
    '↑如果Find_Num這正則的數量是大於 0 ??
        For i = 0 To Find_Num.Count - 1
        '↑設順迴圈!i從0到 Find_Num正則的數量-1 (代表正則的索引號也是0開始)
            If mxa < Find_Num(i).submatches(0) Then
            '↑如果迴圈數正則中 取Pattern = "長(.+?)、" 規則的小括號中的數值,
            '大於mxa這雙精度小數值??
            '找了好久!submatches(0)代表第一個子匹配,即小括號中的數值

               mxa = Find_Num(i).submatches(0)
               '↑mxa的初始值是0,後續迴圈正則經If判斷式比較後,會取得最大值的
            End If
        Next i
    End If
    MsgBox mxa
    Set reg = Nothing
    Set Find_Num = Nothing
End Sub
作者: Andy2483    時間: 2022-12-15 10:36

本帖最後由 Andy2483 於 2022-12-15 10:44 編輯

回復 13# 准提部林


    謝謝前輩指導,後學在此帖學到很多知識
請前輩再指導,謝謝
函數輸入:
[attach]35606[/attach]

結果:
[attach]35607[/attach]

Function GetNum(xS As String, X$, TY$)
'↑自訂函數名GetNum,變數1(xS)是字串,變數2(X)是字串,變數3(TY)是字串
Dim T, k, s%, xD
'↑宣告(T,k,xD)是通用型變數,(s)是短整數
'後學還不能確定%&如何正確使用,可能是防止溢位??

GetNum = ""
'↑令GetNum這自訂函數值是空字元!
'代表的是先不管後面能不能有值,先給空格

xS = Replace(xS, X, "|" & X)
'↑令xS這輸入的變數字串進行字元置換(用輸入的X變數字串換成 "|"符號連接X變數字串)
s = Len(X)
'↑令s這短整數變數是 輸入的X變數字串的字元數
If s = 0 Then Exit Function
'↑如果s字元數是 0,就結束自訂函數
Set xD = CreateObject("Scripting.Dictionary")
'↑令xD是 字典
For Each T In Split(xS & "|", "|")
'↑設順迴圈!令T是 (xS輸入的變數字串連接"|"符號後 被"|"符號分割的一維陣列)陣列子字串
'& "|" 暫不清楚為何要加這個??懇請指導
    If Left(T, s) = X Then
    '↑如果迴圈陣列子字串T的左側 s(輸入的X變數字串的字元數) 的字串,是 輸入的X變數字串??
       k = k + 1
       '↑令k這通用型變數+1
       xD(k) = Val(Mid(T, s + 1))
       '↑令K這數字是key,
       'ITEM是 迴圈陣列子字串T 取從s + 1個字元開始的全部字元,經Val函式轉化的數值
       '學到了
       '1.xD(k) = Val(Mid(T, 1)),Val函式轉化的字串開頭若不是數字,回傳值為0
       '2.Val函式轉化的字串判讀到 可轉化為數值連續字元,之後的字元捨棄

    End If
Next
If k = 0 Then Exit Function
'↑如果k是 0,就結束自訂函數
If UCase(TY) = "MAX" Then
'↑如果函數輸入的TY變數字串是 "MAX" ??
   GetNum = Application.Max(xD.Items)
   '↑令GetNum回傳xD字典裡的items最大值
ElseIf UCase(TY) = "MIN" Then
'↑否則如果函數輸入的TY變數字串是 "MIN" ??
   GetNum = Application.Min(xD.Items)
   '↑令GetNum回傳xD字典裡的items最小值
ElseIf UCase(TY) = "SUM" Then
'↑再否則如果函數輸入的TY變數字串是 "SUM" ??
   GetNum = Application.Sum(xD.Items)
   '↑令GetNum回傳xD字典裡的items平均值
End If
End Function
http://forum.twbts.com/thread-23804-1-1.html
'上鏈結帖用 Application.Volatile 是因為格式變化會影響自訂函數,
'所以將使用者定義的函數標示為易變,
'測試結果是游標格變化就會重算自訂函數


'此帖可以不必使用Application.Volatile,目標格編輯就會回傳值即可
Sub T_20221215()
MsgBox Val("4.21、03/04 12:00 AA-173.25(x)")
End Sub
作者: Andy2483    時間: 2022-12-16 07:41

本帖最後由 Andy2483 於 2022-12-16 07:47 編輯

回復 15# Andy2483


    修正自己的武斷,不求甚解,
不要怪別人不教我們,該檢視自己努力了多少,做錯了多少決定,喪失了多少學習機會
回答錯了,修正回來就好了!

'1.xD(k) = Val(Mid(T, 1)),Val函式轉化的字串開頭若不是數字,回傳值為0
'2.Val函式轉化的字串判讀到 可轉化為數值連續字元,之後的字元捨棄


Sub T_20221216_1() '可以開頭是小數點
MsgBox Val(".21、03/04 12:00 AA-173.25(x)")
End Sub
Sub T_20221216_2() '可以自動Trim掉前方空白字元
MsgBox Val(" 4.21、03/04 12:00 AA-173.25(x)")
End Sub
Sub T_20221216_3() '可以判斷開頭是負符連接小數點
MsgBox Val("-.21、03/04 12:00 AA-173.25(x)")
End Sub
Sub T_20221216_4() '可以判斷開頭是負符
MsgBox Val("-4.21、03/04 12:00 AA-173.25(x)")
End Sub
Sub T_20221216_5() '可以自動Trim掉前後方空白字元
MsgBox Val(" -4.21 、03/04 12:00 AA-173.25(x)")
End Sub
Sub T_20221216_6() '可以判斷開頭是正符
MsgBox Val("+4.21、03/04 12:00 AA-173.25(x)")
End Sub
Sub T_20221216_7() '不做運算
MsgBox Val("+4.21+1、03/04 12:00 AA-173.25(x)")
End Sub
Sub T_20221216_8() '自動去除中間的空白字元
MsgBox Val("+4.21 1 1、03/04 12:00 AA-173.25(x)")
End Sub
Sub T_20221216_9() '不會將日期型式的字串判為日期,且整數的多於0會自動去除
MsgBox Val("03/04 12:00 AA-173.25(x)")
End Sub
Sub T_20221216_10() '不會將時間型式的字串判為時間
MsgBox Val("12:00 AA-173.25(x)")
End Sub
Sub T_20221216_11() '會判別奇怪符號
Workbooks.Add
[A1] = "1200" & ChrW(160) & "00 AA-173.25(x)"
MsgBox Val("1200" & ChrW(160) & "00 AA-173.25(x)")
http://forum.twbts.com/viewthrea ... &from=favorites
End Sub
Sub T_20221216_12() '可以開頭是小數也可以去空省零
MsgBox Val("00 0.21、03/04 12:00 AA-173.25(x)")
End Sub

'如果還有想到補充的,後學會再回來修正,謝謝論壇,謝謝各位前輩
作者: Andy2483    時間: 2022-12-16 11:29

回復 13# 准提部林


    謝謝前輩指導
後學研究前輩的範例陣列公式無法理解,請前輩撥空再指導
請教前輩:
1.是不是在第5大項開始就是陣列?
2.ROW($1:$19)*199-198,199 是什麼意義?
3.為什麼 --TEXT() 前面要有兩個 - 負號 ?

[attach]35609[/attach]

[attach]35610[/attach]
作者: Andy2483    時間: 2022-12-23 11:40

本帖最後由 Andy2483 於 2022-12-23 11:46 編輯

回復 16# Andy2483

補充:
Sub T_20221216_11() '會辨認單引號
MsgBox Val("'4.21、03/04 12:00 AA-173.25(x)")
End Sub
Sub T_20221216_12() '會辨認"^"符號,而且出現 型態不符的偵錯
MsgBox Val("4.21^2、03/04 12:00 AA-173.25(x)")
End Sub
作者: Andy2483    時間: 2022-12-23 12:30

回復 18# Andy2483

現在想得到的除錯方式:
Sub T_20221216_13() '會辨認單"^"符號,而且出現 型態不符的偵錯
MsgBox Val(Replace("4.21^2、03/04 12:00 AA-173.25(x)", "^", ""))
MsgBox Val(Split("4.21^2、03/04 12:00 AA-173.25(x)", "^")(0))
'如果要運算:
MsgBox Val(Split("4.21^2、03/04 12:00 AA-173.25(x)", "^")(0)) ^ Val(Split("4.21^2、03/04 12:00 AA-173.25(x)", "^")(1))
End Sub
作者: Andy2483    時間: 2023-3-8 16:25

本帖最後由 Andy2483 於 2023-3-8 16:39 編輯

回復 15# Andy2483


謝謝 准提部林前輩   
'& "|" 暫不清楚為何要加這個??懇請指導

[D3]="03/04 10:00 AA-179.25(x) 長-4.21、03/04 12:00 AA-173.25(x) 長-3.019、03/05 12:00 AA-179(x) 長-5.169、875.09 長"
[B2]=GetNum(D3,"長","max")=0

======================================
抱歉!好像也不是這原因,繼續探索




歡迎光臨 麻辣家族討論版版 (http://forum.twbts.com/)