Question

I'm currently working on a windows form in VS2010 that is supposed to create UPC-A for new part numbers and store them in a database. So far I'm still trying to get the pieces together and I'm having issues with calculating the check digit. I came up with the following two scenarios:

Scenario 1: Do the calculation the way we currently do it in Excel:

string value = uPCDataSet.UPC.Rows[uPCDataSet.UPC.Rows.Count - 1]["UPCNumber"].ToString();
string manCode = value.Substring(1, 5);
string prodCode = value.Substring(7, 5);
int first = Math.Abs(Convert.ToInt32(value));

while (first >= 10)
first /= 10;

int chkDigitSubtotal;

string UPCNumber = first + manCode + prodCode;

chkDigitSubtotal = Convert.ToInt32((UPCNumber.Substring(1, 1)) + (UPCNumber.Substring(3, 1)) + 
(UPCNumber.Substring(5, 1)) + (UPCNumber.Substring(7, 1)) + (UPCNumber.Substring(9, 1)) + 
(UPCNumber.Substring(11, 1)));

chkDigitSubtotal = (3 * chkDigitSubtotal) + Convert.ToInt32((UPCNumber.Substring(2, 1)) + 
(UPCNumber.Substring(4, 1)) + (UPCNumber.Substring(6, 1)) + (UPCNumber.Substring(8, 1)) + 
(UPCNumber.Substring(10, 1)));

 string chkDigit = ((300 - chkDigitSubtotal).ToString()).Substring(12, 1);

When I run this code, I get an error "Value was either too large or too small for an Int32". I don't understand why since "value" is a varchar with 12 characters (they are all numbers).

Scenario 2: I found a code snipped online. This code works, but gives me the wrong check digit. I'm using a UPC that we calculated using your Excel sheet:

string value = "606891001678"; //valid UPC with check digit
string UPCBody = value.Substring(0, 11);
int sum = 0;
bool odd = true;

for (int i = value.Length - 1; i >= 0; i--)
{
    if (odd == true)
    {
        int tSum = Convert.ToInt32(value[i].ToString()) * 2;

        if (tSum >= 10)
        {
            string tData = tSum.ToString();
            tSum = Convert.ToInt32(tData[0].ToString()) + Convert.ToInt32(tData[1].ToString());
        }
        sum += tSum;
    }
    else
        sum += Convert.ToInt32(value[i].ToString());

    odd = !odd;
}

int result = (((sum / 10)+1) *10) - sum;
result = result % 10;
MessageBox.Show(UPCBody + " & " + result);

In this example the check digit obviously should be 8, but it returns 2. I've spent pretty much all day on this and could use some advice. Why am I getting the error on the first scenario and why am I getting a different check digit in the second scenario from what it should be?

Thanks in advance for your help!

Chris

EDIT:

I deleted two previous edits since the code was flawed in a sense that I didn't get the correct results. I found out that we use Azalea barcodes and they have their own method of calculating the check digit (see ChkDigitSubtotal). So the below code works and gives me the correct check digit for my scenario. I think this code will work up to chkDigitSubtotal for all UPC-A calculations. Thanks to Harrison for his great guidance and resourceful answer!

string value = uPCDataSet.UPC.Rows[uPCDataSet.UPC.Rows.Count - 1]
["UPCNumber"].ToString();
long chkDigitOdd;
long chkDigitEven;
long chkDigitSubtotal;
string UPCNumber = value.Substring(0, 11);
chkDigitOdd = Convert.ToInt64(UPCNumber.Substring(0, 1)) +
Convert.ToInt64(UPCNumber.Substring(2, 1)) + Convert.ToInt64(UPCNumber.Substring(4, 1)) 
+ Convert.ToInt64(UPCNumber.Substring(6, 1)) + Convert.ToInt64(UPCNumber.Substring(8, 
1)) + Convert.ToInt64(UPCNumber.Substring(10, 1));
chkDigitOdd = (3 * chkDigitOdd);
chkDigitEven = Convert.ToInt64(UPCNumber.Substring(1, 1)) + 
Convert.ToInt64(UPCNumber.Substring(3, 1)) + Convert.ToInt64(UPCNumber.Substring(5, 1)) 
+ Convert.ToInt64(UPCNumber.Substring(7, 1)) + Convert.ToInt64(UPCNumber.Substring(9, 
1));
chkDigitSubtotal = (300-(chkDigitEven + chkDigitOdd));
string chkDigit = chkDigitSubtotal.ToString();
chkDigit = chkDigit.Substring(chkDigit.Length - 1, 1);
Était-ce utile?

La solution

Based on what I'm reading on wikipedia your doing the calculation incorrectly in the first example.

  • String.Substring + String.Subtring or "1" + "1" = "11". You are looking for 1+1=2. You need to convert each substring to int prior to adding.

+ Operator (C# Reference)

Binary + operators are predefined for numeric and string types. For numeric types, + computes the sum of its two operands. When one or both operands are of type string, + concatenates the string representations of the operands.

  • String.Substring is 0 based so you are missing the String.Substring(0,1) for your even digits

String.Substring Method

startIndex: The zero-based starting character position of a substring in this instance.

  • Your checkdigit string attempts to take the 12th digit of a string which is less than 12 digits. Also, this isn't the calculation as seen in the link. It's looking for 10 - mod 10 of that number. This is also happening in your updated edit in the line

string chkDigit = ((300 - chkDigitSubtotal).ToString()).Substring(12, 1);

You are attempting to take a Substring from the 12th 0 based character, or 13th character for a length of 1. However, the value of chkDigitSubtotal will not be that large/long.

As far as your error, As Golden Dragon states in his answer your are converting a 12 characcter string to a number, which won't fit into an Int32 and you should use a long.

int first = Math.Abs(Convert.ToInt32(value));

goes to

long first = Math.Abs(Convert.ToInt64(value));

I would check your calculation is actually functioning logically in the previous steps first.

Update

In your edit 2 it looks like your last line has the variables around the % operator reversed. You want to take the remainder of 109 divided by 10 (which is 9) and your code takes the remainder of 10 divided by 109 (which is 0) So change.

chkDigitSubtotal = 10 - (10 % (chkDigitEven + chkDigitOdd));

to

chkDigitSubtotal = 10 - ((chkDigitEven + chkDigitOdd) % 10);

Now 10 - 9 = 1 which is your checkDigit.

Autres conseils

If value is a 12 digit long string, then it is much too large to fit into an int. Use a long instead

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top