European Article Number

El número de artículo europeo (en inglés European Article Number o EAN) es un sistema de códigos de barras adoptado por más de cien países y cerca de un millón de empresas. En el año 2005, la asociación EAN se fusionó con la UCC para formar una nueva y única organización mundial identificada como GS1, con sede en Bélgica.

Estructura y partes 

El código EAN más usual es EAN-13, constituido por trece (13) dígitos y con una estructura dividida en cuatro partes:

 Los primeros dígitos del código de barras EAN identifican el país que otorgó el código, no el país de origen del producto. Por ejemplo, en Chile se encarga de ello una empresa responsable adscrita al sistema EAN y su código es el 780.
 Composición del código: 
Código del país: en donde radica la empresa, compuesto por tres (3) dígitos.
 Código de empresa: es un número compuesto por cuatro o cinco dígitos, que identifica al propietario de la marca. Es asignado por la asociación de fabricantes y distribuidores (AECOC).
 Código de producto: completa los doce primeros dígitos.
 Dígito de control: para comprobar el dígito de control (por ejemplo, inmediatamente después de leer un código de barras mediante un escáner), numeramos los dígitos de derecha a izquierda. A continuación se suman los dígitos de las posiciones impares, el resultado se multiplica por 3, y se le suman los dígitos de las posiciones pares. Se busca decena inmediatamente superior y se le resta el resultado obtenido. El resultado final es el dígito de control. Si el resultado es múltiplo de 10 el dígito de control será cero (0).

Por ejemplo, para 123456789041 el dígito de control será:

 Numeramos de derecha a izquierda: 140987654321
 Suma de los números en los lugares Impares: 1 + 0 + 8 + 6 + 4 + 2 = 21
 Multiplicado (por 3): 21 × 3 = 63
 Suma de los números en los lugares pares: 4 + 9 + 7 + 5 + 3 + 1 = 29
 Suma total: 63 + 29 = 92
 Decena inmediatamente superior: 100
 Dígito de control: 100 - 92 = 8

El código quedará así: 1234567890418.

Algoritmo informático

Perl 
# Cálculo del dígito de control EAN
my $ean      = '750863367001';             # Valor de prueba
my $checksum = 1000;           
my $i        = 0;

for my $digit (split //, reverse $ean) {   # Recorremos el $ean de forma inversa, dígito por dígito
    $checksum                              # Modificamos $checksum
       -= $i++ % 2                         # según la posición del dígito:
        ? $digit                           # posición impar
        : $digit*3                         # posición par
        ;
}

$checksum %= 10;                           # Ajustamos a la decena inmediatamente inferior

print "Dígito de control: $checksum\n";
print "Código EAN: $ean$checksum\n";

PHP 
// Cálculo del dígito de control EAN
function ean13_checksum ($message) {
  $checksum = 0;
  foreach (str_split(strrev($message)) as $pos => $val) {
    $checksum += $val * (3 - 2 * ($pos % 2));
  }
  return ((10 - ($checksum % 10)) % 10);
}

// Valor de prueba (sin dígito de control)
$ean = '931804231236';
echo 'Digito de control: ', ean13_checksum($ean);

C# 
// Cálculo del dígito de control EAN
string ean = "123456789012";
int sum = 0;
int sumOdd = 0;
var digit = 0;

for (int i = ean.Length; i >= 1; i--)
{
    digit = Convert.ToInt32(ean.Substring(i - 1, 1));
    if (i % 2 != 0)
    {
       sumOdd += digit;
    }
    else
    {
       sum += digit;
    }
}

digit = (sumOdd) + (sum * 3);

int checkSum = (10 - (digit % 10)) % 10;
Console.Write("Dígito de control: " + checkSum.ToString());

Python 3 
EAN = "123456789041"

def ean_checksum(code: str) -> int:
    digits = [int(i) for i in reversed(code)]
    return (10 - (3 * sum(digits[0::2]) + (sum(digits[1::2])))) % 10

print(f"Dígito de control: {ean_checksum(EAN)}")

Python 
EAN = "123456789041"

def eanCheck(ean):
    checksum = 0
    for i, digit in enumerate(reversed(ean)):
        checksum += int(digit) * 3 if (i % 2 == 0) else int(digit)
    
    return (10 - (checksum % 10)) % 10

print "Digito de control: %d" %eanCheck(EAN)

Visual Basic 6.0 
'Verifica que sea un código EAN válido

Function EanValido(ByVal Ean As String) As Boolean
    Dim Sum As Integer, Digit As Integer, i As Integer
    
    Sum = 0
    For i = 1 To Len(Ean) - 1
        Digit = Mid(Ean, i, 1)
        Sum = Sum + Digit * IIf(i Mod 2 = 0, 3, 1)
    Next
 
    EanValido = Right(Ean, 1) = ((10 - Sum Mod 10) Mod 10)
End Function

JavaScript
// Cálculo del dígito de control EAN
function ean13_checksum(message) {
    var checksum = 0;
    message = message.split('').reverse();
    for(var pos in message){
        checksum += message[pos] * (3 - 2 * (pos % 2));
    }
    return ((10 - (checksum % 10 )) % 10);
}
// Valor de prueba (sin dígito de control)
var ean = '123456789041';
console.log(ean13_checksum(ean));

Bash compatible 
ean13_checksum ()
{
	local EAN="$1"
	local Test=''
	local CurDigit=''
	local CurReversePos=''
	local CurPos=''
	local OddSum=''
	local EvenSum=''
	local TotalSum=''
	local UpperTenth=''
	local Value=0
	
	Test="$(printf '%s' "$EAN" | sed -e 's|[^0123456789]||g')"
	if [ "$EAN" != "" ] && [ "$Test" = "$EAN" ] ; then
		CurDigitNr=${#EAN}
		CurReversePos=1
		while [ $CurDigitNr -gt 0 ] ; do
			CurDigit="$(printf '%s' "$EAN" | cut -c ${CurDigitNr}-${CurDigitNr})"
			if [ $((CurReversePos % 2)) -ne 0 ] ; then
				OddSum=$((OddSum + CurDigit))
			else
				EvenSum=$((EvenSum + CurDigit))
			fi
			CurReversePos=$((CurReversePos + 1))
			CurDigitNr=$((CurDigitNr - 1))
		done
		OddSum=$((OddSum * 3))
		TotalSum=$((OddSum + EvenSum))
		if [ ${#TotalSum} -eq 1 ] ; then
			UpperTenth=10
		else
			UpperTenth="$(printf '%s' "$TotalSum" | sed -e 's|.$||')"
			UpperTenth="$((UpperTenth + 1))0"
		fi
		Value=$((UpperTenth - TotalSum))
		CurPos=${#Value}
		echo "$Value" | cut -c ${CurPos}-${CurPos}
	fi
}

ean13_checksum 123456789041

ABAP 
    CALL FUNCTION 'MARA_EAN11'
         EXPORTING
              P_MATNR      = MARA-MATNR
              P_NUMTP      = MARA-NUMTP
              P_EAN11      = MARA-EAN11
              P_MEINH      = MARA-MEINS
              RET_EAN11    = LMARA-EAN11
              RET_NUMTP    = LMARA-NUMTP
              BINPT_IN     = SY-BINPT
              P_MESSAGE    = ' '
              ERROR_FLAG   = EAN_FEHLERFLG
              P_HERKUNFT   = 'A'         " Für Abmessungen / EAN
              GDS_RELEVANT = MARA-GDS_RELEVANT
         IMPORTING
            P_NUMTP      = MARA-NUMTP
            P_EAN11      = MARA-EAN11
            VB_FLAG_MEAN = RMMG2-VB_MEAN
            MSGID        = MSGID       " s. weiter unten
            MSGTY        = MSGTY
            MSGNO        = MSGNO
            MSGV1        = MSGV1
            MSGV2        = MSGV2
            MSGV3        = MSGV3
            MSGV4        = MSGV4
       TABLES
            MARM_EAN     = MARM_EAN
            MEAN_ME_TAB  = MEAN_ME_TAB " NEU: AHE 24.10.95
          ME_TAB       = ME_TAB
          YDMEAN       = YDMEAN
     EXCEPTIONS
          EAN_ERROR    = 1
          OTHERS       = 2....

Delphi 
// Cálculo del dígito de control EAN
function cc_CalcDV_Ean(Ean: String): Integer; 
{ Calcula y devuelve el dígito verificador de una cadena de código EAN13 o EAN8
  Devcuelve -1 en caso de ser incorrecto. }
var
  SP, SI, I, L:Integer;
  Impar: Boolean;
begin
  L:= Length(Ean);
  if (L=8) or (L=13) then
    begin
    SI:= 0;
    SP:= 0;
    I:= L-1;
    Impar:= Odd(L);
    repeat                                     // Bucle para sumar los valores discriminando posiciones pares e impares
      if Impar then SI:= SI + StrToInt(Ean[I]) else SP:= SP + StrToInt(Ean[I]);
      Impar:= not Impar;
      I:= I - 1;
    until I =0;
    if Impar then SI:= SI*3 else SP:= SP*3;    // Multiplica por tres según la longitud del código
    Result:= 10-(SI+SP) mod 10;                // Calcula el dígito de verificación
  end else Result:= -1;
end;

Java 
/**
 * Cálculo del código de control
 */
private int controlCodeCalculator(String firstTwelveDigits)
{
     char[] charDigits = firstTwelveDigits.toCharArray();
     int[] ean13 =
     {
        1, 3
     };
     int sum = 0;
     for(int i = 0; i < charDigits.length; i++)
     {
         sum += Character.getNumericValue(charDigits[i]) * ean13[i % 2];
     }
     int checksum = 10 - sum % 10;

     if(checksum == 10)
         checksum = 0;

     return checksum;
}

SQL 
DECLARE @initialBarcode VARCHAR(13), @auxBarcode VARCHAR(13), @finalBarcode VARCHAR(13)

SET @auxBarcode =  REVERSE(@initialBarcode)

DECLARE @verifierCode INT = 0
SELECT 
	@verifierCode = CASE 
		WHEN i % 2 = 0 THEN 
			@verifierCode + SUBSTRING(@auxBarcode, i, 1) 
		ELSE
			@verifierCode + (SUBSTRING(@auxBarcode, i, 1) * 3)
	END
FROM  dbo.NumbersTable(1,12,1) --- FALTA ESTO EN EL SQL

SET @verifierCode = RIGHT((10 - RIGHT(@verifierCode,1)),1)

SET @finalBarcode = CONCAT(@initialBarcode, @verifierCode)

RETURN @finalBarcode

MATLAB 
if isnumeric(ean)
    ean = sprintf('%013d', ean);
end;
checksum = sum((ean(1:end-1)-'0').*(rem([0:11],2)*2+1));
if rem(10 - (rem(checksum,10)), 10) ~= ean(13)-'0'
    disp('El checksum no parece ser correcto')
end;

Visual FoxPro 
FUNCTION DIGITO_VERIFICADOR_EAN
LPARAMETERS tcCodigoBarras
LOCAL lnSuma, lnI, lnDigito, lnDigitoVerificador
   
  lnSuma = 0
   
  FOR lnI = Len(tcCodigoBarras) TO 1 STEP -1
    lnDigito = Val(Substr(tcCodigoBarras, lnI, 1))
    IF (Mod(Len(tcCodigoBarras) - lnI + 1, 2)) <> 0 THEN
      lnSuma = lnSuma + lnDigito * 3
    ELSE
      lnSuma = lnSuma + lnDigito
    ENDIF
  ENDFOR
   
  lnDigitoVerificador = Mod(10 - Mod(lnSuma, 10), 10)
   
  RETURN (lnDigitoVerificador)
ENDFUNC

Excel 
El ejemplo calcula un EAN13 para la celda A1, si fuera 123456789041 añadiría un 8 como dígito de control
=SI(LARGO(A1)>12;"MAS de 13";SI(ESERROR(A1*1);"NO NUMERICO";CONCATENAR(REPETIR(0;12-LARGO(A1));A1)&RESIDUO((10-(DERECHA(((SI.ERROR(VALOR(EXTRAEB(TEXTO(A1;0);2;1));"0")+(SI.ERROR(VALOR(EXTRAEB(TEXTO(A1;0);4;1));"0"))+(SI.ERROR(VALOR(EXTRAEB(TEXTO(A1;0);6;1));"0"))+(SI.ERROR(VALOR(EXTRAEB(TEXTO(A1;0);8;1));"0"))+(SI.ERROR(VALOR(EXTRAEB(TEXTO(A1;0);10;1));"0"))+(SI.ERROR(VALOR(EXTRAEB(TEXTO(A1;0);12;1));"0")))*3)+(SI.ERROR(VALOR(EXTRAEB(TEXTO(A1;0);1;1));"0")+(SI.ERROR(VALOR(EXTRAEB(TEXTO(A1;0);3;1));"0"))+(SI.ERROR(VALOR(EXTRAEB(TEXTO(A1;0);5;1));"0"))+(SI.ERROR(VALOR(EXTRAEB(TEXTO(A1;0);7;1));"0"))+(SI.ERROR(VALOR(EXTRAEB(TEXTO(A1;0);9;1));"0"))+(SI.ERROR(VALOR(EXTRAEB(TEXTO(A1;0);11;1));"0")));1)));10)))

LibreOffice Calc & Google Sheets
El ejemplo calcula un EAN13 para la celda A6, si fuera 123456789041 añadiría un 8 como dígito de control
=IF(ISNUMBER(VALUE(A6));
    IF(LEN(A6)=12
       ;A6&IF(MOD(
              (MID(A6;2;1)+MID(A6;4;1)+MID(A6;6;1)+
              MID(A6;8;1)+MID(A6;10;1)+MID(A6;12;1))*3+
              LEFT(A6;1)+MID(A6;3;1)+MID(A6;5;1)+
              MID(A6;7;1)+MID(A6;9;1)+MID(A6;11;1)
                       ;10)=0;0;10-MOD(
              (MID(A6;2;1)+MID(A6;4;1)+MID(A6;6;1)+
              MID(A6;8;1)+MID(A6;10;1)+MID(A6;12;1))*3+
              LEFT(A6;1)+MID(A6;3;1)+MID(A6;5;1)+
              MID(A6;7;1)+MID(A6;9;1)+MID(A6;11;1)
                       ;10)
           )
       ;"Deben ser 12 dígitos")
    ;"Deben ser dígitos")

C 
// Se presupone que la variable ean contiene un código EAN válido

char ean[13] = "123456789041";
char *car = ean + 12;
int par = !0;
int control = 0;
int num;

while(car-- - ean) {
    num = *car - '0';
    if(par) num *= 3;
    par = !par;
    control += num;
}

return 10 - control % 10;

Ruby 
# controlar que el código EAN sea válido

def ean_valid?(code)
    digits = code.split('').map(&:to_i);
    sum = (0...(digits.size-1)).sum{|i| digits[i] * (i.odd? ? 3 : 1)}
    digits.last == (10 - sum) % 10 
end

Dart 
// controlar que el código EAN sea válido

bool  eanValid(String code) {
    final digits = code.split('').map((x) => int.parse(x)).toList();

    var sum = 0;
    for (var i = 0; i < digits.length - 1; i++) {
      sum += digits[i] * (i.isOdd ? 3 : 1);
    }

    return digits.last == (10 - sum) % 10;
  }

Véase también 

 ASIN
 Código de barras
 Tienda de autoservicio
 GS1-128 (antes Ean-128)

Referencias

Enlaces externos 

 EAN International, ahora GS1 International 
 Directorio de sitios en todo el mundo
 Prefijos EAN por país
 EAN database 

Identificadores internacionales
Códigos de barras
Algoritmos de suma de verificación