2020年8月1日 星期六

EXCEL VBA與Python 文字檔(csv, touchstone...)讀入,LF and CRLF不同系統的換行字元, Python Lesson 101


    最近也開始跟風學習Python這個話題性很高的程式語言,平常其實最常用到的工具是OFFICE系列,Word, PowerPoint, Excel 三本柱,Excel本身內建很多強大的函數,可以進行統計計算,位元與一些數學運算,但資料來源可能是來自生產端或實驗室的輸出文字檔(log file)。

EXCEL VBA 檔案輸入 LINE INPUT

   
    首先有一個檔案text1.txt內容如下,! 後面接的是註解內容不處理,後面的檔案格式是用Comma "," 隔開,也就是縮為的CSV Comma Separated Value檔案格式。
! MacGyFu Python Learning Notes
! data format [d1],[d2],[d3],[d4]
ff,12,10,20
33,11,44,55
66,77,88,99
ac,f1,78,8c
     如果用Notepad開啟可以看到的內容如下。

    Excel 我們先拉一個Button,然後程式碼如下,只要用到 VB code的檔案開啟Open()與Line Input ()這兩個函數,每一行讀入的時候利用VB內建的字串函數Mid()判斷每一行的字元是不是"!",如果不是在進行處理把每一行的用Comma隔開的資料傳到sorting()傳回一維陣列,然後把資料貼到Excel上面。

Private Sub CommandButton1_Click()
Dim file As String
Dim in_str As String
Dim i, j As Integer
file = "text1.txt"
Dim data() As String
Open ThisWorkbook.Path & "\" & file For Input As #1
i = 0
j = 0
Do While Not EOF(1)
    Line Input #1, in_str    'Line Input
    If Mid(in_str11) = "!" Then
        'Do Nothing
    Else
    Call sorting(data, in_str",")
    For i = 0 To UBound(data)
        Cells(6 + j1 + i) = data(i)
    Next i
    j = j + 1
    End If
Loop

Close #1

End Sub
        以下是sorting函數的寫法,當然這些都是一些字串的處理,每個人寫出來的會不太一樣,
Public Sub sorting(ByRef value() As String, ByVal in_str As String, Optional mark As String = " ")
    Dim i As Integer
    Dim j As Integer
    Dim temp As String
    temp = in_str
    i = 1
    j = 0
    ReDim value(j)
    For i = 1 To Len(temp)
        If Mid(temp, i1) = mark Then
            j = j + 1
            i = i + 1
            ReDim Preserve value(j)
        End If
        value(j) = value(j) & Mid(temp, i1)
    Next i

    For i = 0 To UBound(value)
        value(i) = Trim(value(i))
    Next i
End Sub

        讓我們看一下執行的結果

EXCEL VBA LF and CRLF換行字元處理

    但很多時候會遇到以下的問題,大部的工廠測試機台的系統是跑在UNIX系統,UNIX系統的換行字元為LF (\n),但Windows系統則是CRLF (\r\n),所以會遇到用微軟系列的文字處理函數會遇到他認為這個檔案只有"一行"

        所以這裡處理就要修改一下,Line Input改成Input()逐字讀入,直到讀到LF (Chr(10))就換行丟入sorting()處理,所以整個程式流程等於是自己寫了Line Input()這個Function。

Line Input()        逐行行入

Input()                逐字讀入

Private Sub CommandButton1_Click()
Dim file As String
Dim in_str As String
Dim i, j As Integer
Dim temp As String
file = "text1_LF.txt"
Dim data() As String
Open ThisWorkbook.Path & "\" & file For Input As #1
i = 0
j = 0
Do While Not EOF(1)
    'Line Input #1, in_str    'Line Input
    temp = ""
    in_str = ""
    Do Until temp = Chr(10) Or EOF(1)
        temp = Input(1, #1)
        in_str = in_str & temp
    Loop
    in_str = Replace(in_strChr(10), "")
    If Mid(in_str11) = "!" Then
        'Do Nothing
    Else
    Call sorting(data, in_str",")
    For i = 0 To UBound(data)
        Cells(6 + j1 + i) = data(i)
    Next i
    j = j + 1
    End If
Loop

Close #1

End Sub

Python 怎麼寫?

        Python研究了幾天,在檔案處理部分其實差不多,但針對CSV已經有現成的函數可以使用,只要import csv就可以開始呼叫使用,但新手就練習一下如果自己寫會長的怎樣,主程式內容如下,基本上跟VBA的流程一樣,呼叫語法有點不一樣而已。
#Open File
try:
    with open("text1.txt","r",encoding="utf-8"as f:
        #case 1 read all
        count=0
        column=2
        for result in f: 
            temp =  result.replace("\n","")
            if temp == "":
                pass
            elif temp[0] == "!":
                pass
            else:
                row=sorting(temp,",")
                print (count,"  ",row)
                print ("index 0 >",row[0])      
                count+=1
            
            
except IOError as err:
    print ("檔案開啟錯誤 Err=",err)
finally:
    print("結束")

        其中的sorting寫法如下
def sorting(instr,delimiter =","):
    matrix=[]
    i=0
    j=0
    temp=""
    while (i<len(instr)):
        if instr[i] != delimiter:
            temp=temp+instr[i]
            i+=1
        elif instr[i] == delimiter:
            matrix.append(temp)
            j+=1
            i+=1
            temp=""
        if i > (len(instr)-1):
                matrix.append(temp)
                break  
    return matrix

        最後執行的結果如下,可以把每一行的資料分開,後續就可以針對每個資料進行運算處理。

Python內建CSV函數

        其實針對csv檔案,Python也有提供現成的csv處理,只要import csv後就可以使用,所以就少寫sorting()這個函數,跑出來的結果也一樣,另外Python的檔案處理則不用特別處理這個問題LF與CRLF這兩種差別。

import csv
#Open File
try:
    with open("text1.txt","r",encoding="utf-8"as f:
        #case 1 read all
        count=0
        column=3
        rows = csv.reader(f, delimiter=',')
        for row in rows: 
            if row[0][0] != "!":
                count+=1
                print(row)
                print ("index 0 >",row[0])           
except IOError as err:
    print ("檔案開啟錯誤 Err=",err)
finally:
    print("結束")



Touchstone S Parameter 

        如果有現成的可以用當然直接用,但沒有的時候還是要自己處理了,例如RF工程師會常遇到S parameter (Touch Stone)可以參考Keysight Save Trace Data in Touchstone Format的文件,這類型的文件檔案之間比較類似文字對齊的方式,讓人可以直接閱讀方便,所以每行間的資料並不是用Comma ","或固定空格" ",每一筆資料可能有不同的空格或插入TAB讓資料排列整齊。


        我們用上述處理csv的方式 (python用的是內建csv函數),分隔符號delimiter用空格符號" ",跑出來的結果如下,因為空格符號可能會連續2-3個,所以會誤認有些資料是"空格"。


EXCEL VBA 處理Touch Stone Like


        所以在這樣的Case我們可以假設連續出現的Delimiter 為相同的分隔訊號,直到下次非分隔訊號為止,我們可以改寫sorting的程式碼如下。
Public Sub sorting(ByRef value() As String, ByVal in_str As String, Optional mark As String = " ")
    Dim i As Integer
    Dim j As Integer
    Dim temp As String
    Dim Duplicate_Mark_Remove As Boolean
    Duplicate_Mark_Remove = False
    temp = in_str
    i = 1
    j = 0
    ReDim value(j)
    For i = 1 To Len(temp)
        If Mid(temp, i1) <> mark And (Duplicate_Mark_Remove = FalseThen
            value(j) = value(j) & Mid(temp, i1)
        ElseIf Mid(temp, i1) = mark And (Duplicate_Mark_Remove = FalseThen
            Duplicate_Mark_Remove = True
        ElseIf Mid(temp, i1) = mark And (Duplicate_Mark_Remove = TrueThen
            Duplicate_Mark_Remove = True
        ElseIf Mid(temp, i1) <> mark And (Duplicate_Mark_Remove = TrueThen
            Duplicate_Mark_Remove = False
            j = j + 1
            ReDim Preserve value(j)
            value(j) = value(j) & Mid(temp, i1)
        End If
    Next i

    For i = 0 To UBound(value)
        value(i) = Trim(value(i))
    Next i
End Sub

        執行結果如下,就可以得到每一筆資料,然後後面要計算Gain, 矩陣反轉,並聯與串聯等計算。



Python 處理Touch Stone Like

        其實是EXCEL VBA Code把一樣的動作邏輯改成Python的語法,

def sorting(instr,delimiter =","):
    matrix=[]
    i=0
    j=0
    temp=""
    Duplicate_Delimiter_Flag = False
    while (i<len(instr)):
        if (instr[i] != delimiter and (Duplicate_Delimiter_Flag == False)):
            temp=temp+instr[i]
            i+=1
        elif (instr[i] == delimiter and (Duplicate_Delimiter_Flag == False)):
            Duplicate_Delimiter_Flag =True
            i+=1
        elif (instr[i] == delimiter and (Duplicate_Delimiter_Flag == True)):
            Duplicate_Delimiter_Flag = True
            i=i+1
        elif (instr[i] != delimiter and (Duplicate_Delimiter_Flag == True)):
            Duplicate_Delimiter_Flag = False
            matrix.append(temp)
            j+=1
            temp=""
            temp=temp+instr[i]
            i+=1
            
        if i > (len(instr)-1):
                matrix.append(temp)
                break  
    return matrix

        執行結果就可以得到預期的效果了


        這次練習的EXCEL VBA與Python py檔我就放在Google雲端硬碟有需要的在自己下載參考。




.
.
......

沒有留言:

張貼留言

熱門文章