問題從最初的「答案」
考慮場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
我相信這是可能的VBA,但爲40年,因爲我用最後使用COBOL和我已經忘記了「PIC S9(03)COMP-3」的確切含義。我知道你想要一個簽名的3位數字,但是什麼格式是「comp-3」,VBA是一種編程語言。這與編程軟件有什麼不同? –
(1)在搜索完網頁和我記憶中的灰塵角落之後,我想我知道你尋求的格式。是的,你可以用VBA做到這一點。但是,如果供應商可以處理comp-3數字字段,則他們可以比您更容易地執行轉換。你爲什麼要進行這種轉換? (2)您的輸入說明不充分。字段1到5是否有前導符號或尾隨符號? –
託尼我可以誠實地說我對包裝領域不熟悉,所以我不確定什麼格式是「comp-3」。我想在Excel中使用VBA創建此過程而不是Excel以外的程序。現在它可以讓供應商長達兩天的時間將返回文件作爲打包字段發回給我們。節省我們的時間和成本我想知道這是否是我可以學習如何去做的事情。是的,文本文件已經有了領先的空間。 – CLAuto