• 关于UPC E条码的校验


    关于UPC E条码的知识可以参照BlueSky老师的空间,非常感谢BlueSky老师的耐心讲解。

    下面这篇文章是BlueSky对条码的讲解,其中第四部分是关于UPC E的。

     http://user.qzone.qq.com/26425753/blog/1252850602

    从BlueSky老师的讲述来看,UPC E条码应该是8位的,只不过UPC E的第一位一定是0,并且校验位用A,B子集的排列来表示(这跟EAN13的第一位的形成方式是一样的),所以条码的条空只表示6位数字,但是加上系统位0和A,B子集排列代表的校验位,条码本身代表的数字含义一定是8位的。所以我不太明白AX里在做条码设置的时候UPC E为什么规定成6位的?用扫描枪扫描出来的是8位的数字。。。

    基本设置->设置->条码设置

    这样给商品添加UPC-E条码的时候,就只能输入6位了,否则会报错说位数不对,问题是即便把0和校验位去掉了,输入6位数字,还是会报错说校验位不对。

    BlueSky老师的一篇文章介绍了校验位的生成算法:

    http://user.qzone.qq.com/26425753/blog/1251297004

    在AX中UPC和EAN类型的编码的校验位算法在类BarcodeEAN_UPC的validateCheckDigit

    代码
    protected boolean validateCheckDigit(BarCodeString barCodeString)
    {
        boolean             ret 
    = true;
        str                 tmp;
        ;

        
    if (strlen(barCodeString) != this.strlen())
            
    return true;    // Actually an error, but has already been reported.

        barcodeStr 
    = this.encodeString(substr(barCodeString,1,this.strlen()));

        tmp 
    = Barcode::insertModulo10CheckDigit(barCodeString, this.strlen());
        
    if (tmp != barCodeString)
            ret 
    = checkFailed(strfmt("@SYS76957", substr(barCodeString, this.strlen(), 1), substr(tmp, this.strlen(), 1)));

        
    return ret;
    }

    AX的代码就是实现了BlueSky老师介绍的校验位生成算法,类BarCode的静态方法insertModulo10CheckDigit:

    代码
    public client server static str insertModulo10CheckDigit(str s_in, Integer stringLength)
    {
        Integer checkDigit 
    = 0;
        Integer counter;
        Integer temp;

        Integer digit(Integer position)
        {
            
    return any2int(substr(s_in,stringLength + 1 - position,1));
        }
        ;

        counter 
    = 2;
        
    while (counter <= stringLength)
        {
            checkDigit 
    += digit(counter);
            counter 
    += 2;
        }
        checkDigit 
    = 3 * checkDigit;

        counter 
    = 3;
        
    while (counter <= stringLength)
        {
            checkDigit 
    += digit(counter);
            counter 
    += 2;
        }

        temp 
    = checkDigit mod 10;
        
    if (temp)
            checkDigit 
    = 10 - temp;
        
    else
            checkDigit 
    = 0;

        
    return substr(s_in,1,stringLength - 1+ num2str(checkDigit,1,0,0,0);
    }

     EAN8,EAN13以及UPC-A用这个算法生成校验位都没有问题,UPC-E直接用这个算法就有问题了,如果按照AX的要求输入去掉首位和校验位的六位数字,生成的校验位显然不符合要求。

    UPC-E要生成校验位必须首先还原成UPC-A,然后再用上面的算法才能生成正确的校验位,还原的算法很简单,按照前面提到的BlueSky老师的文章里介绍UPC-A到UPC-E的压缩算法反过程回去就可以了,X++代码如下:

    代码
    private BarCodeString upce2UPCA(BarCodeString _barCodeString)
    {
        BarCodeString           barCodeString;
        ;
        
    switch(str2int(substr(_barCodeString,strlen(_barCodeString)-1,1)))
        {
            
    case 0:
            
    case 1:
            
    case 2:
            {
                barCodeString 
    = substr(_barCodeString,1,3)
                                    
    +substr(_barCodeString,strlen(_barCodeString)-1,1)
                                        
    +'0000'
                                            
    +substr(_barCodeString,4,3)
                                                
    +substr(_barCodeString,strlen(_barCodeString),1);
                
    break;
            }
            
    case 3:
            {
                 barCodeString 
    = substr(_barCodeString,1,4)
                                    
    +'00000'
                                        
    +substr(_barCodeString,5,2)
                                            
    +substr(_barCodeString,strlen(_barCodeString),1);
                
    break;
            }
            
    case 4:
            {
                barCodeString 
    = substr(_barCodeString,1,5)
                                    
    +'00000'
                                        
    +substr(_barCodeString,6,1)
                                            
    +substr(_barCodeString,strlen(_barCodeString),1);
                
    break;
            }
            
    case 5:
            
    case 6:
            
    case 7:
            
    case 8:
            
    case 9:
            {
                barCodeString 
    = substr(_barCodeString,1,6)
                                    
    +'0000'
                                        
    +substr(_barCodeString,7,2);

                
    break;
            }
            
    default:
                
    throw error("");
        }
        
    return barCodeString;


    }

    然后在类BarcodeUPCEvalidateCheckDigit

    代码
    protected boolean validateCheckDigit(BarCodeString barCodeString)
    {
        boolean ret;
        str                 tmp;
        str                 barCodeStringLocal;
        ;
        barcodeStr 
    = this.encodeString(substr(barCodeString,2,this.strlen()));

        barCodeStringLocal 
    = this.upce2UPCA(barCodeString);

        tmp 
    = Barcode::insertModulo10CheckDigit(barCodeStringLocal, 12);


        
    if (substr(tmp,strlen(tmp),1!= substr(barCodeString,strlen(barCodeString),1))
            ret 
    = checkFailed(strfmt("@SYS76957", substr(barCodeString, this.strlen(), 1), substr(tmp, strlen(tmp), 1)));

        
    return ret;
    }

     其实在类BarcodeEAN_UPC的encodeStr的前半部部分就是用来计算校验位的,算法大同小异,首先还原成UPC-A,然后再计算得到校验位,根据校验位得到各个数字对应的打印的字符。这个方法是按照UPC-E为六位计算得到打印字符的,所以也需要改一下,把传入的字符去头舍尾变成六位。

    if (len != this.strlen())
            
    return '';

    _stringIn 
    = subStr(_stringIn,2,6);

    修改一下表BarcodeSetup的fieldModifiedBarcodeType方法,让其当类型为UPCE时,最大和最小长度设置为8。

    代码
    public void fieldModifiedBarcodeType()
    {
        Barcode     barcode;
        ;
        
    switch(this.BarcodeType)
        {
            
    case BarcodeType::UPCA              :
                
    this.MinimumLength  = 12;
                
    this.MaximumLength  = 12;
                
    break;
            
    case BarcodeType::UPCE              :
                
    this.MinimumLength  = 8;
                
    this.MaximumLength  = 8;
                
    break;
            
    case BarcodeType::EAN13             :
                
    this.MinimumLength  = 13;
                
    this.MaximumLength  = 13;
                
    break;
            
    case BarcodeType::EAN8              :
                
    this.MinimumLength  = 8;
                
    this.MaximumLength  = 8;
                
    break;
        }

        barcode 
    = this.barcode();
        
    if (this.FontName && !barcode.validateFontName(this.FontName))
            
    this.FontName = '';

        
    if (!this.FontName)
            
    this.FontName = barcode.defaultFont();

    }

    UPCE条码应该还是有很多地方用的,AX在全世界也有很多用户,如果这是个bug的话,应该早就发现了,所以我觉得可能是我某个地方理解错了,但是又实在找不到相关文档,也只能这么从代码上这么改了,还望知道其中原委的高人指点。

  • 相关阅读:
    今天是周日,一如既往的在加班
    懒出来的框架
    把Visio文档中形状信息导出到XML文件的VBA代码
    DataGridView多线程更新数据的问题的解决办法
    为VS定制一个自己的代码生成器
    安装VS2012之后自己开发的自定义工具没法使用问题的解决办法
    通过RSA进行私钥加密公钥解密算法的进一步改进
    程序员在职场 该反思了吗?
    图片与字节数组相互转换的方法
    jQuery Ajax 方法调用 Asp.Net WebService 的详细例子
  • 原文地址:https://www.cnblogs.com/Farseer1215/p/1733560.html
Copyright © 2020-2023  润新知