2015-05-14 83 views
0

目前我有一個宏將一個excel文件分解爲固定的NL ASCII文本文件,該文件是一個78字節文件27924塊大小。然後我必須將文件發送給供應商以將數據打包到66字節文件。 (包括每個打包字段前面的空格。)請參閱下面的佈局。這可以在VBA中完成,還是需要在編程軟件中完成?將數據轉換爲打包格式的VBA代碼


我開始用ASCII:

Field # - Start Pos - Length 
    1 -  1  - 4 
    2 -  5  - 6 
    3 - 11  - 2 
    4 - 13  - 6 
    5 - 19  - 6 
    6 - 25  - 1 
    7 - 26  - 21 
    8 - 47  - 10 
    9 - 57  - 1 
    10 - 58  - 1 
    11 - 59  - 20 

和需要(包裝領域)結束

Field # - Start Pos - Length - Cobol format  
    1 - 1  - 2 - pic s9(03)comp-3 
    2 - 3  - 3 - pic s9(05)comp-3 
    3 - 6  - 1 - pic s9(01)comp-3 
    4 - 7  - 3 - pic s9(05)comp-3 
    5 - 10  - 3 - pic s9(05)comp-3 
    6 - 13  - 1 - pic x(01)  
    7 - 14  - 21 - pic x(21)  
    8 - 35  - 10 - pic x(10)  
    9 - 45  - 1 - pic x(01)  
    10 - 46  - 1 - pic x(01)  
    11 - 47  - 20 - pic x(20)  

預先感謝您爲您可以對任何援助提供。

+0

我相信這是可能的VBA,但爲40年,因爲我用最後使用COBOL和我已經忘記了「PIC S9(03)COMP-3」的確切含義。我知道你想要一個簽名的3位數字,但是什麼格式是「comp-3」,VBA是一種編程語言。這與編程軟件有什麼不同? –

+0

(1)在搜索完網頁和我記憶中的灰塵角落之後,我想我知道你尋求的格式。是的,你可以用VBA做到這一點。但是,如果供應商可以處理comp-3數字字段,則他們可以比您更容易地執行轉換。你爲什麼要進行這種轉換? (2)您的輸入說明不充分。字段1到5是否有前導符號或尾隨符號? –

+0

託尼我可以誠實地說我對包裝領域不熟悉,所以我不確定什麼格式是「comp-3」。我想在Excel中使用VBA創建此過程而不是Excel以外的程序。現在它可以讓供應商長達兩天的時間將返回文件作爲打包字段發回給我們。節省我們的時間和成本我想知道這是否是我可以學習如何去做的事情。是的,文本文件已經有了領先的空間。 – CLAuto

回答

0

問題從最初的「答案」

考慮場1剩餘:

  • 如果該值是負123此舉行「-123」或「123-」?
  • 輸出格式爲2個字節,對於「s9(3)comp-3」是正確的。但是「每個包裝領域前面都沒有空間」。

「固定NL ASCII文本文件」是否意味着您有78個字節行被換行符分隔?

你說你「有一個宏,打破了Excel文件」。你想更新該宏還是想要宏讀取文本文件並輸出一個Cobol文件?

請更新您的問題

可能的答案

我假設你在工作中貼出你的問題,你會不會回答我的問題直到星期一回答我的問題。下週我將有限的互聯網接入,所以我張貼我希望是一個滿意的答案。我會盡可能迴應你的迴應。

我對你的問題的解釋是你有一個宏,它建立一個358行的文件,每行78個字節以換行符結尾。每行包含11個字段,其中前六個字段是數字。您使用轉換服務來創建一個文件,除了每行的六個數字字段從ASCII字符串轉換爲Cobol的comp3格式外,其他文件都是一樣的。

在你的宏,你將有這樣的話:

RowCrnt = RowCrnt & Range.Value 

其中RowCrnt是在該行正在修建準備輸出和Range.Value是從工作底稿獲得的ASCII數字串的字符串。

我寫一個函數,所以你可以用替換上述聲明:

RowCrnt = RowCrnt & AsciiToComp3(P1, P2, P3, Range.Value) 

以後我會解釋P1,P2和P3。通過這種更改,由宏創建的文件應該採用Cobol格式。

我有肉眼檢查,我的功能創建我期望的輸出。但是,我沒有獨立的測試方法。也許我對comp3格式的理解是錯誤的。也許有一個難以辨認的細微錯誤。也許有更多的轉換比我欣賞。

假設您的現有宏爲不同的數據集創建文件A1,A2等。您的供應商已將文件A1,A2和A3轉換爲文件B1,B2和B3。您需要檢查由更新的宏匹配B1,B2和B3創建的文件。

如果我的函數發現不喜歡的東西,它使用Debug.Assert False來停止執行。這在開發過程中非常方便,但它會嚇倒生產宏中的用戶。應該達到這些Debug.Assert False語句中的任何一個,因爲它們表示在使用該函數時或在它給予處理的數據中有錯誤。這些都不應該發生,所以你可以決定不改變功能。只有你能知道什麼是合適的。

參數P1,P2和P3指定要轉換的ASCII值的格式。該函數創建的comp3格式是最小的,它將保存這樣一個ASCII值。這應該是令人滿意的數據。如果您希望comp3值更大,請指定ASCII數據的最大大小,使其大於實際最大值。

P1標識在ASCII數據符號的位置:

  • -1表示前導符號。例如:-123或+123或123.
  • 0表示無符號
  • 1表示拖尾符號。例如:123-或123+或123.

即使未使用尾隨符號,Comp3格式也會保留半字節。

P2是整數位數的最大值。因此,如果最大值爲999,則P2 = 3,如果最大值爲99,999,則P2 = 5。

P3是最大小數位數。如果ASCII值是整數,則設置P3 = 0。在ASCII值中使用本地小數點符號(句號或逗號)。

好運

Option Explicit 
Function AsciiToComp3(ByVal SignFmt As Long, ByVal NumIntegerDigitsFmt, _ 
         ByVal NumDecimalDigitsFmt As Long, _ 
         ByVal AsciiValue As String) As String 

    ' * Returns a string which is a Comp-3 version of AsciiValue. 

    ' * SignFmt    -1 if AsciiValue has an optional leading sign. For 
    '       example 12.34 or -12.34 
    '      0 if AsciiValue has no sign. For example 12.34 
    '      1 if AsciiValue has an optional trailinging sign. 
    '       For example 12.34 or 12.34- 
    ' * NumIntegerDigitsFmt If AsciiValue may not contain a decimal separator, 
    '      the maximum number of digits. 
    '      If AsciiValue may contain a decimal separator, the 
    '      maximum number of digits to the left of the decimal 
    '      separator. The decimal separator is 
    '      Application.DecimalSeparator which returns "." or' 
    '      "," according to local conventions. 
    ' * NumDecimalDigitsFmt If AsciiValue may not contain a decimal separator, 0. 
    '      If AsciiValue may contain a decimal separator, the 
    '      maximum number of digits to the right of the decimal 
    '      separator. 
    ' * AsciiValue   The value to be converted to comp-3 format. This 
    '      string must confirm to the format defined by the 
    '      first three parameters. For example: it can only 
    '      contain a sign if SignFmt indicates it can; it can 
    '      only contain a decimal separator if 
    '      NumDecimalDigitsFmt > 0 and the number of digits 
    '      cannot exceed the numbers indicated by 
    '      NumIntegerDigitsFmt and NumDecimalDigitsFmt. 

    ' The return string will be sized to hold the largest Ascii value. Increase 
    ' NumIntegerDigits and NumDecimalDigits above the true maximum size of 
    ' AsciiValue if a larger return string is required. If the return value is to 
    ' be signed but AsciiValue is not signed then set Sign to -1 or 1 as though 
    ' it could be signed. 

    ' The number of bytes in the return string will be: 
    ' (NumIntegerDigits + NumDecimalDigits + 1)/2 rounded up. 
    ' The "+ 1" is for the sign. Space is always allocated for a sign even if 
    ' the value is unsigned. 
    ' If the expression has to be rounded up, there will be space for one more 
    ' integer digit than requested. 

    Dim Digit As String 
    Dim NumericValue As String 
    Dim PosDest As Long 
    Dim Pos As Long 
    Dim PosDecimal As Long 
    Dim Positive As Boolean 
    Dim PosSrc As Long 
    Dim ReturnValue As String 

    ' Enlarge NumIntegerDigits if necessary 
    If (NumIntegerDigitsFmt + NumDecimalDigitsFmt + 1) Mod 2 = 1 Then 
    ' Make output string a whole number of bytes 
    NumIntegerDigitsFmt = NumIntegerDigitsFmt + 1 
    End If 

    ' Decode AsciiValue 

    ' If sign present, record value and remove from AsciiValue 
    Select Case SignFmt 
    Case -1 
     Select Case Left(AsciiValue, 1) 
     Case "-" 
      Positive = False 
      AsciiValue = Mid(AsciiValue, 2) ' Remove sign 
     Case "+" 
      Positive = True 
      AsciiValue = Mid(AsciiValue, 2) ' Remove sign 
     Case Else 
      Positive = True 
     End Select 
    Case 0 
     Positive = True 
    Case 1 
     Select Case Right(AsciiValue, 1) 
     Case "-" 
      Positive = False 
      AsciiValue = Mid(AsciiValue, 1, Len(AsciiValue) - 1) ' Remove sign 
     Case "+" 
      Positive = True 
      AsciiValue = Mid(AsciiValue, 1, Len(AsciiValue) - 1) ' Remove sign 
     Case Else 
      Positive = True 
     End Select 
    Case Else 
     Debug.Assert False ' Call error. SignFmt not -1, 0 or 1. 
    End Select 

    PosDecimal = InStr(1, AsciiValue, Application.DecimalSeparator) 

    If PosDecimal > 0 Then 
    If NumDecimalDigitsFmt = 0 Then 
     ' AsciiValue contains decimal separator but specification says it 
     ' should not 
     Debug.Assert False 
     AsciiToComp3 = "Error" 
     Exit Function 
    End If 
    If PosDecimal > NumIntegerDigitsFmt Or _ 
     Len(AsciiValue) - PosDecimal > NumDecimalDigitsFmt Then 
     ' AsciiValue contains more integer digits or more decimal digits than 
     ' allowed by specification 
     Debug.Assert False 
     AsciiToComp3 = "Error" 
     Exit Function 
    End If 
    ' Pad integer part of AsciiValue with leading zeros to NumIntegerDigits, 
    ' discard decimal and 
    ' pad decimal part with trailing digits to NumDecimalDigits 
    NumericValue = Right(String(NumIntegerDigitsFmt, "0") & Mid(AsciiValue, 1, PosDecimal - 1), NumIntegerDigitsFmt) & _ 
        Left(Mid(AsciiValue, PosDecimal + 1) & String(NumDecimalDigitsFmt, "0"), NumDecimalDigitsFmt) 
    Else 
    ' AsciiValue is all integer 
    If Len(AsciiValue) > NumIntegerDigitsFmt Then 
     ' AsciiValur contains more integer digits than allowed by specification 
     Debug.Assert False 
     AsciiToComp3 = "Error" 
     Exit Function 
    End If 
    ' Pad AsciiValue with leading zeros to maximum length 
    NumericValue = Right(String(NumIntegerDigitsFmt, "0") & AsciiValue, NumIntegerDigitsFmt) 
    If NumDecimalDigitsFmt > 0 Then 
     NumericValue = NumericValue & String(NumDecimalDigitsFmt, "0") 
    End If 
    End If 

    ' Create Return value of required length but full of zeros. 
    ReturnValue = String((NumIntegerDigitsFmt + NumDecimalDigitsFmt + 1) \ 2, Chr$(0)) 

    ' Pack Ascii string "ABCEFG" with each pair of ASCII digits becoming one byte 
    ' of output string. Ascii string has odd number of digits with last half byte 
    ' reserved for sign. 
    ' ABCDEFG -> ab cd ef g 
    PosSrc = 1 
    PosDest = 1 
    Do While True 
    ' Handle digits that are stored in lefthand half of bytes 
    Digit = Mid(NumericValue, PosSrc, 1) 
    If Digit < "0" Or Digit > "9" Then 
    ' Not a decimal digit 
     Debug.Assert False 
     AsciiToComp3 = "Error" 
     Exit Function 
    End If 
    Mid(ReturnValue, PosDest, 1) = Chr(Val(Digit) * 16) 

    PosSrc = PosSrc + 1 
    If PosSrc > Len(NumericValue) Then 
     ' All digits handled 
     Exit Do 
    End If 

    ' Handle digits that are stored in righthand half of bytes 
    Digit = Mid(NumericValue, PosSrc, 1) 
    If Digit < "0" Or Digit > "9" Then 
    ' Not a decimal digit 
     Debug.Assert False 
     AsciiToComp3 = "Error" 
     Exit Function 
    End If 
    Mid(ReturnValue, PosDest, 1) = Chr$(Asc(Mid(ReturnValue, PosDest, 1)) Or Val(Digit)) 

    PosSrc = PosSrc + 1 
    PosDest = PosDest + 1 

    Loop 

    If SignFmt = 0 Then 
    ' Comp3 string is unsigned. Half byte for sign already zero so no action required. 
    Else 
    If Positive Then 
     Mid(ReturnValue, PosDest, 1) = Chr$(Asc(Mid(ReturnValue, PosDest, 1)) Or &HC) 
    Else 
     Mid(ReturnValue, PosDest, 1) = Chr$(Asc(Mid(ReturnValue, PosDest, 1)) Or &HD) 
    End If 
    End If 

    AsciiToComp3 = ReturnValue 

End Function