# USPS Address Correction Service (ACS) - Check Digit Sum code

I have to implement a check digit sum number for this address correction service.  When a alpha+number is given, it should convert to this check digit algorithm  Eg if I input ID1234, the check digit sum would be :
ID12343

The specifications to generate this result is contained in the attached file.  I would like to invite all Gurus and anyone or everyone to give a try on this assignment. I would award 1,000 points if the rules allow it.
Also the project seems to interesting but my expertise does not allow me to try it.
Thanks.

Extract-from-pub8a.doc
###### Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

retiredAuthor Commented:
I edited a typo in the above question
0
Commented:
Option Explicit

Private Sub Command1_Click()
MsgBox CheckSumString("JLSTMS6796")
MsgBox CheckSumString("TMS1112/62")

End Sub

Private Function CheckSumString(ByVal strText As String) As String
Dim b() As Byte
Dim i As Integer
Dim strDigits As String
Dim intTotal As Integer

strText = Replace(strText, " ", "")
strText = StrConv(strText, vbUpperCase)
b = StrConv(strText, vbFromUnicode)
For i = 0 To UBound(b)
b(i) = b(i) And 15
Next

For i = 0 To UBound(b) Step 2
b(i) = b(i) * 2
Next

For i = 0 To UBound(b)
strDigits = strDigits & b(i)
Next

For i = 1 To Len(strDigits)
intTotal = intTotal + CInt(Mid\$(strDigits, i, 1))
Next

CheckSumString = strText & CStr(10 - CInt(Right\$(CStr(intTotal), 1)))

End Function
0
Senior Software Engineer (Avast)Commented:
A C version...

BTW: Example 3 for MOD10 appears to be wrong.
``````#include <stdio.h>
#include <string.h>

int calc(char * pcur1)
{
int total = 0;
char * pcur2 = pcur1;
int idx = 1;

while(*pcur1)
{
if(' ' == *pcur1)
{
if(pcur2 < pcur1) pcur2 = pcur1;
while(*pcur2 && ' ' == *pcur2) ++ pcur2;
*pcur1 = *pcur2;
*pcur2 = ' ';
}

if(*pcur1)
{
*pcur1 &= 0x0F;
if(idx % 2) *pcur1 *= 2;
total += (*pcur1)/10;
total += (*pcur1)%10;
++idx;
++pcur1;
}
}

return 10 - (total%10);
}

typedef char BUFFER[20];

int main()
{
char *testdata[] = {
"J L S T M S 6 7 9 6",
"T M S 1 1 1 2 / 6 2",
"2 1 8 X N 9 1 L M S" /* The documentation for this one seems wrong!!! */
};

size_t const testdata_len = sizeof(testdata) / sizeof(testdata[0]);

size_t idx = 0;
for( ; idx < testdata_len; ++idx)
{
BUFFER td;
strcpy(td, testdata[idx]);
printf("Keyline: %s (Check Digit = %d)\n", testdata[idx], calc(td));
}

return 0;
}
``````
0
retiredAuthor Commented:
This is for Paul Hews' code:
Testing of different keylines gave wrong results.  This is the test data used.  Could you please check and let me know if your code is correctly implemented :
Result by Access      Result by Keyline
MsgBox CheckSumString("ABC999MM/32")      ABC999MM/321      PASS
MsgBox CheckSumString("ANIT0281")            ANIT028110                          pass
MsgBox CheckSumString("0012////8")            012////81                        PASS
MsgBox CheckSumString("811NIS0001119")      811NIS00011190      PASS
MsgBox CheckSumString("12345678907")      123456789072      PASS
MsgBox CheckSumString("09876543213")      098765432137      PASS

MsgBox CheckSumString("218XN91LMS")      218XN91LMS5      FAIL SHOULD BE 4
MsgBox CheckSumString("123456")            1234569            PASS
MsgBox CheckSumString("ID235")            ID2359            PASS
MsgBox CheckSumString("QWERTY")            QWERTY1            PASS
MsgBox CheckSumString("218XN91LMS")               218XN91LMS5                          FAIL SHOULD BE 5 GAVE A DIFF ANSWER EACH TIME
MsgBox CheckSumString("JLSTMS6796")      JLSTMS67969      PASS
MsgBox CheckSumString("TMS1112/62")      TMS1112/623      PASS

There is a program called KEYLINE.EXE that is available at the USPS site and if you wish you coudl email me and I will email this program to you.  This program spits out the result for any value that you type in.
Also I have the original publication by USPS which is in pdf forwat, so I could also email this to you.

Thanks.
0
Senior Software Engineer (Avast)Commented:
What about the C code I provided? You did put this in the C Zone.
0
Senior Software Engineer (Avast)Commented:
BTW: Did you see the note I made in my code?
"2 1 8 X N 9 1 L M S" /* The documentation for this one seems wrong!!! */

The example in the documentation is inconsistent with itself (look at the example, it seems to go wrong in the bit where it adds the values together).

You state: -

MsgBox CheckSumString("218XN91LMS") 218XN91LMS5 FAIL SHOULD BE 4
MsgBox CheckSumString("218XN91LMS") 218XN91LMS5 FAIL SHOULD BE 5 GAVE A DIFF

There seems to be some inconsistency here, no?

My C code generates the output below. I believe 5 to be the correct result for the above.
``````Keyline: J L S T M S 6 7 9 6 (Check Digit = 9)
Keyline: T M S 1 1 1 2 / 6 2 (Check Digit = 3)
Keyline: 2 1 8 X N 9 1 L M S (Check Digit = 5)
``````
0
Commented:
The keyline app mentioned above gives 4.  But I'm with evilrix, it's not consistent with the MOD 10 method stated in the docs.

>it seems to go wrong in the bit where it adds the values together).

Exactly.  Here's the example from the docs:

Weighted Value 4 1 16 8 28 9 2 12 26 3
Sum 4 +1 +1+6 +8 +1+0 +9 +2 +1+2 +2+6 +3 = 46

The sum given above is not based on the weighted digits.  The 1 and 0 should be 2 and 9  The actual sum is
4+1+1+6+8+2+8+9+2+1+2+2+6+3 = 55

And the check digit should be 5.
0
retiredAuthor Commented:
Both of you are right.  There is a typo on my part.
When the keyline 218XN91LMS is input, the answer should be 218XN91LMS4
This is what the documentation of the USPS gives as to test our code.
Thanks.

EvilRix : Would you be able to give me your solution in VB code please, so that I coudl test your algorithm too.
Thanks.
0
Commented:
>Both of you are right.  There is a typo on my part.

Looks to me like a mistake in the documentation, not on your part.  The algorithm as stated in the docs returns a check digit of 5 not 4  (See post above which references the documentation.)
0
Senior Software Engineer (Avast)Commented:
>> EvilRix : Would you be able to give me your solution in VB code please, so that I could test your algorithm too.
I don't know VB - sorry. You posted this in the C Zone as well as the VB Zone so I think it was reasonable for me to assume you could work with a C solution.
0
Commented:
Somehow missed the note about the letter "N":

Note: The value of letter N in an odd position, when weighted, becomes
14 x 2 = 28. The digits 2 and 8 are added, yielding 10. This sum is then
further rendered as 1 + 0, not the sum of 10.
``````Option Explicit

Private Sub Command1_Click()
Dim vArrayTest As Variant
Dim i As Integer
Dim strTest As String

vArrayTest = Array("ABC999MM/321", _
"ANIT0281", _
"0012////8", _
"811NIS0001119", _
"12345678907", _
"1234569", _
"ID2359", _
"QWERTY1", _
"218XN91LMS4", _
"TMS1112/623")

For i = 0 To UBound(vArrayTest)
strTest = vArrayTest(i)
If CheckSumString(Left(strTest, Len(strTest) - 1)) = strTest Then
Debug.Print strTest & " PASS"
Else
Debug.Print strTest & "FAIL " & CheckSumString(Left(strTest, Len(strTest) - 1))
End If
Next

End Sub

Private Function CheckSumString(ByVal strText As String) As String
Dim b() As Byte
Dim i As Integer
Dim strDigits As String
Dim intTotal As Integer

strText = Replace(strText, " ", "")
strText = StrConv(strText, vbUpperCase)
b = StrConv(strText, vbFromUnicode)
For i = 0 To UBound(b)
b(i) = b(i) And 15
Next

For i = 0 To UBound(b) Step 2
b(i) = b(i) * 2
Next

For i = 0 To UBound(b)
If b(i) = 28 And i Mod 2 = 0 Then
'            Debug.Print strText, i, b(i)
strDigits = strDigits & "10"
'            Debug.Print
Else
strDigits = strDigits & b(i)
End If
Next

'    Debug.Print "Digits: " & strDigits

For i = 1 To Len(strDigits)
intTotal = intTotal + CInt(Mid\$(strDigits, i, 1))
Next

CheckSumString = strText & CStr(10 - CInt(Right\$(CStr(intTotal), 1)))

End Function

Private Sub Command2_Click()
Dim i As Integer
For i = Asc("/") To Asc("Z")
Debug.Print Chr(i), i And 15
Next
End Sub
``````
0

Experts Exchange Solution brought to you by

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Senior Software Engineer (Avast)Commented:
>> Somehow missed the note about the letter "N":
Ooo, me too but since the OP seems to want a VB solution I'll not attempt to fix it -- unless a C solution is confirmed as an acceptable alternative.
0
retiredAuthor Commented:
My salutations to Paul.  This guy Paul is a Genius to be able to write this complicated code.
0
Senior Software Engineer (Avast)Commented:
Can I suggest that next time you don't put a Q in an unrelated Zone. I spent 1/2 hour writing the C code !!!
0
retiredAuthor Commented:
Evilrix,
My apologies.
Jothy
0
Senior Software Engineer (Avast)Commented:
>> My apologies
No worries.
Thanks.
0
Commented:
evilrix, whenever I see a question posted in two disparate zones, I try to check the question history before spending any amount of time working the question.  The new question wizard often suggests some pretty weird zone combinations.
0
Senior Software Engineer (Avast)Commented:
>> The new question wizard often suggests some pretty weird zone combinations.
Understood. It was just a little frustrating spending time writing and testing code for, ostensibly, no good reason. No harm done though. I guess we can all learn something from this :)

Cheers.

-Rx.
0
###### It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic Classic

From novice to tech pro — start learning today.