Codificador de código de barras código 39

16

Escriba una función o programa que codifique una cadena en un código de barras de formato Código 39 , donde cada carácter se codifica como cinco barras separadas por cuatro espacios. O dos de las barras y uno de los espacios son anchos y otros son estrechos (códigos 10 * 4), o tres de los espacios son anchos y ninguna de las barras son (4 códigos). Esto proporciona 44 códigos diferentes, de los cuales uno es un código reservado que se utiliza para denotar el inicio y el final de la cadena codificada.

El reto

La entrada es una cadena que contiene solo caracteres del conjunto

1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ-. +/$%

La salida es la cadena codificada como una cadena de código de barras. La brecha estrecha y las brechas entre caracteres son un espacio único y una brecha ancha es tres espacios. La barra estrecha es la secuencia de bytes UTF-8 para el carácter Unicode "Bloque completo", █, es decir, 0xE2 0x96 0x88y la barra ancha tiene tres secuencias / caracteres de bytes ( ███). La lista completa de códigos es:

      Spaces
      0100 0010 0001 1000 1011 1101 1110 0111
Bars
00000                       +    /    $   %
10001   1    A    K    U
01001   2    B    L    V
11000   3    C    M    W
00101   4    D    N    X
10100   5    E    O    Y
01100   6    F    P    Z
00011   7    G    Q    -
10010   8    H    R    .
01010   9    I    S  space          1=wide
00110   0    J    T  start/end      0=narrow

Las barras y los espacios están intercalados, comenzando en una barra, por ejemplo, Q es

bar   0 0 0  1     1 
code  █ █ █ ███   ███
space  0 0 0    1

Después de codificar todos los caracteres, la cadena se delimita en ambos extremos con █ █ ███ ███ █. El espacio entre caracteres, un solo espacio, se inserta entre cada letra. Su solución puede generar espacios finales y una nueva línea final (en ese orden).

Ejemplos

""     → "█   █ ███ ███ █ █   █ ███ ███ █"

"A"    → "█   █ ███ ███ █ ███ █ █   █ ███ █   █ ███ ███ █"

"C++"  → "█   █ ███ ███ █ ███ ███ █   █ █ █   █ █   █   █ █   █ █   █   █ █   █ ███ ███ █"

"GOLF" → "█   █ ███ ███ █ █ █ █   ███ ███ ███ █ ███ █   █ █ ███ █ █   ███ █ ███ ███   █ █ █   █ ███ ███ █"

Los formatos de entrada / salida estándar están permitidos y las lagunas estándar están prohibidas. Este es el , por lo que gana el código más corto medido en bytes.

Angs
fuente
1
¿Podemos usar un carácter ASCII imprimible (puede elegir cuál permitir) en lugar de █?
Erik the Outgolfer
Para un lenguaje como BrainFuck, ¿qué cuenta como "un uso"?
l4m2
1
@Angs quise decir en la salida básicamente, no en el código. No es muy justo penalizar los usos del #personaje, ya que, por ejemplo, "#"no es la única razón por la que podría usarse en un idioma.
Erik the Outgolfer
@EriktheOutgolfer Lo que quise decir era en literales de cadena y similares, pero teniendo en cuenta el punto de l4m2, podría ser mejor no permitirlo. Después de todo, ¿hay algún idioma que no pueda generar tres bytes?
Angs

Respuestas:

7

JavaScript (ES6), 225 212 bytes

Guardado 4 bytes gracias a @ l4m2

s=>`#${s}#`.replace(/./g,c=>'0202020202'.replace(/./g,(j,k)=>[C='█',C+C+C,' ','   '][(i="%+/$U1AKV2BLW3CMX4DNY5EOZ6FP-7GQ.8HR 9IS#0JT".indexOf(c),[170,257,260,5,272,17,20,320,65,68,80][i>>2]^2<<i%4*2)>>k&1|j]))

Pruébalo en línea!

¿Cómo?

La tabla se puede reorganizar de modo que la máscara binaria de 9 bits del personaje se deduzca rápidamente de su fila y columna utilizando la siguiente fórmula:

n = m XOR (2 << k)

con:

  m  | k: 0   2   4   6
-----+------------------      Examples:
 170 |    %   +   /   $
 257 |    U   1   A   K         'G' = 320 XOR (2 << 4) = 320 XOR 32 = 352
 260 |    V   2   B   L
   5 |    W   3   C   M         '+' = 170 XOR (2 << 2) = 170 XOR 8  = 162
 272 |    X   4   D   N
  17 |    Y   5   E   O
  20 |    Z   6   F   P
 320 |    -   7   G   Q
  65 |    .   8   H   R
  68 |   spc  9   I   S
  80 |    #   0   J   T
Arnauld
fuente
s=>`#${s}#`.replace(/./g,c=>'0202020202'.replace(/./g,(j,k)=>[C='#',C+C+C,' ',' '][(i="%+/$U1AKV2BLW3CMX4DNY5EOZ6FP-7GQ.8HR 9IS#0JT".indexOf(c),[,257,260,5,272,17,20,320,65,68,80][i>>2]|(2<<i%4*2^(i<4)*170))>>k&1|j]))(221)
l4m2
@ l4m2 Eso no parece ser válido. Sin embargo, he logrado encontrar una solución para 221 bytes .
Erik the Outgolfer
@EriktheOutgolfer Creo que eso es básicamente lo que l4m2 envió con un bloque completo en lugar de '#'. ¿O me estoy perdiendo algo?
Arnauld
@Arnauld Su original no se espacia correctamente.
Erik the Outgolfer
3

Rojo , 452 445 bytes

func[s][q: func[x y z][append/dup x y z]append insert s"*""*"b:
func[n][v: copy[]until[append v n % 2 * 2 + 1
1 > n: n / 2]q v 1 5 - length? v
reverse v]a: q":1234567890:ABCDEFGHIJ:KLMNOPQRST:UVWXYZ-. *"" "44
a/45: #"+"a/56: #"/"a/67: #"$"a/78: #"%"foreach t s[i: index? find a t
k: b pick[0 17 9 24 5 20 12 3 18 10 6]either 0 = j: i % 11[11][j]m:
b pick[8 4 2 16 22 26 28 14]i - 1 / 11 + 1 z: copy""repeat n 5[q z"█"k/(n)
q z" "m/(n)]prin z]]

Pruébalo en línea!

Intentaré jugar más al golf, pero no espero mucho de esta ingenua solución.

Galen Ivanov
fuente
2

Java 10, 455 bytes

s->{String r="",R=r;for(var c:("~"+s+"~").split(""))r+=r.format("%9s",Long.toString(new int[]{148,289,97,352,49,304,112,37,292,100,52,265,73,328,25,280,88,13,268,76,28,259,67,322,19,274,82,7,262,70,22,385,193,448,145,400,208,133,388,196,138,162,168,42}["~1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ-. +/$%".indexOf(c)],2)).replace(' ','0');for(int l=r.length(),i=0,c;i<l;R+=""+(i%9%2<1?c<49?"█":"███":c<49?" ":"   ")+(i%9>7&++i<l?" ":""))c=r.charAt(i);return R;}

Pruébalo en línea.

Explicación:

s->{                     // Method with String as both parameter and return-type
  String r="",           //  Temp-String, staring empty
         R=r;            //  Result-String, starting empty as well
  for(var c:("~"+s+"~")  //  Prepend and append "~" to the input
            .split(""))  //  And loop over each character
    r+=r.format("%9s",Long.toString( 
                         //   Convert the following integer to a 9-bit binary String:
       new int[]{148,289,97,352,49,304,112,37,292,100,52,
                 265,73,328,25,280,88,13,268,76,28,259,67,322,
                 19,274,82,7,262,70,22,385,193,448,145,400,208,
                 133,388,196,138,162,168,42}
                         //    Array containing all decimal values of the binary Strings
       ["~1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ-. +/$%".indexOf(c)]
                         //    with the index based on the current character
   ,2)).replace(' ','0');
                         //   (also part of the integer to 9-bit binary String conversion)
  for(int l=r.length(),i=0,c;i<l;
                         //  Loop `i` over the temp-String
      R+=                //    After every iteration: append the following to the result:
         ""+(i%9%2<1?    //     If `i` modulo-9 modulo-2 is 0:
              c<49?      //      And `c` is '0':
               "█"       //       Append a single block
              :          //      Else:
               "███"     //       Append three blocks
             :c<49?      //     Else-if `c` is '0':
              " "        //      Append a single space
             :           //     Else:
              "   ")     //      Append three spaces
         +(i%9>7         //     If `i` modulo-9 is 8,
           &++i<l?       //     and this is not the very last character
            " "          //      Append a space delimiter
           :             //     Else:
            ""))         //      Append nothing more
    c=r.charAt(i);       //   Set `c` to the current character in `r`
  return R;}             //  Return the result
Kevin Cruijssen
fuente
2

C (gcc) , 311 , 303 bytes

(*P)()=printf;i;j;w;m[]={170,257,260,5,272,17,20,320,65,68,80};char*b=" \0\xE2\x96\x88",*t="%+/$U1AKV2BLW3CMX4DNY5EOZ6FP-7GQ.8HR 9IS#0JT",*c;p(x){j=256;w=2;while(j){P(b+w);if(x&1){P(b+w);P(b+w);}x/=2;j>>=1;w=2*!w;}P(" ");}f(char*_){p(82);for(c=_;*c;c++){i=strchr(t,*c)-t;p(m[i>>2]^(2<<(i&3)*2));}p(82);}

Pruébalo en línea!

-8 gracias a ceilingcat

Utiliza la estrategia de codificación de la respuesta de Arnauld. El enlace TIO incluye un -winterruptor y una placa repetitiva para eliminar las advertencias, que son innecesarias y, por lo tanto, no están incluidas en el puntaje.

Aparte del esquema de codificación explicado por Arnauld, el otro truco aquí es mantener la wvariable como alternar entre 2 y 0 ( w=2*!w). Esto me permite elegir entre la primera y la segunda secuencia b. El primero es un espacio, el segundo es el rectángulo lleno.

LambdaBeta
fuente
inteligente, deberías publicarlo :)
LambdaBeta
2

C (gcc) , 241 239 227 213 207 bytes

#define P printf(i%2?" ":"█")
i;p(x){for(i=9;i--;x/=2)P,x&1&&P+P;P;}f(char*_){p(82);for(char*t="%+/$U1AKV2BLW3CMX4DNY5EOZ6FP-7GQ.8HR 9IS#0JT";*_;p(L"ªāĄ\5Đ\21\24ŀADP"[i/4]^2<<i%4*2))i=index(t,*_++)-t;p(82);}

Pruébalo en línea!

Basado en la implementación de @ LambdaBeta .

Ligeramente menos golfizado:

#define P printf(i%2?" ":"█")
i;
p(x){
 for(i=9;i--;x/=2)
  P,
  x&1&&
   P+
   P;
 P;
}
f(char*_){
 p(82);
 for(char*t="%+/$U1AKV2BLW3CMX4DNY5EOZ6FP-7GQ.8HR 9IS#0JT";*_;p(L"ªāĄ\5Đ\21\24ŀADP"[i/4]^2<<i%4*2))
  i=index(t,*_++)-t;
 p(82);
}
techo
fuente
1

Carbón , 90 bytes

⪫EE⪫**S⌕⁺⁺⭆…αχ﹪⊕μχα-. *+/$%ι⪫E⁵⁺⎇μ× ∨⁼›ι³⁹⁼²﹪⁻÷ι∨›ι³⁹χμ⁴¦³ω×█∨›ι³⁹∨§↨℅§.6':+3<-59ι²⊕μ³ω 

Pruébalo en línea! Nota: espacio final. El enlace es a la versión detallada del código. Explicación:

⪫EE⪫**S...⪫E⁵⁺...ω 

Envuelva la cadena de entrada en *s y luego mapee sobre ella dos veces, finalmente uniendo el resultado con espacios. Para el segundo mapa, hay un mapa adicional sobre el rango implícito 0..4, donde se concatenan dos subcadenas, y esos resultados se unen con la constante de cadena vacía predefinida.

⌕⁺⁺⭆…αχ﹪⊕μχα-. *+/$%ι

Para el primer mapa interno, cree una cadena formada tomando los dígitos incrementados, el alfabeto en mayúscula y los símbolos -. *+/$%, y busque la posición del carácter de entrada mapeado. Por ejemplo,C++ se asignaría a [12, 40, 40].

⎇μ× ∨⁼›ι³⁹⁼²﹪⁻÷ι∨›ι³⁹χμ⁴¦³ω

La primera subcadena representa los espacios antes de las barras. No hay nada antes de la primera barra, pero las otras barras dependen de la posición del carácter de entrada asignado: si tiene más de 39, entonces solo un lugar tiene un solo espacio, mientras que si tiene menos de 40, solo un lugar tiene tres espacios, y la posición también se convierte en una columna dividiéndola por 10. Si la columna y el índice del bucle difieren entre 2 (módulo 4), entonces ese es el lugar extraño.

×█∨›ι³⁹∨§↨℅§.6':+3<-59ι²⊕μ³

La segunda subcadena representa las barras. Si la posición es superior a 39, siempre hay una barra; de lo contrario, la posición se busca en una matriz de bits asignados a caracteres. Por ejemplo, si la posición es 12, entonces eso se indexa circularmente al carácter ', que está 100111en binario, lo que indica barras anchas en las columnas 1 y 2. (El inicio 1se ignora, simplemente garantiza un recuento de bits constante).

Neil
fuente
1

Perl 5 , 244 bytes

$l="{ ,   ,...,.........}"x9;@h{$",qw($ % + - . /),0..9,'',A..Z}=(<"$l">)[q{..=9...Z.>>...J=9..j.%r1...=).[.>=-..Ux?V.^=8.>.6o+ax_.=(..B=,..Yx6..b=(..#r'p.^...G.<=,..Sx5B.\=(.V.It..z:..-z.=<6.}=~s/./ord$&/gre=~/.{6}/g];s/^|./$h{$&} /g;$\=$h{''}

Pruébalo en línea!

Contiene muchos caracteres no imprimibles y de alto byte, el enlace TIO proporciona una xxdrepresentación. Esperaba que esto hubiera terminado más pequeño, y todavía podría empaquetar los datos de una manera más eficiente, así que veré cómo me va. Esto acumula todas las permutaciones de " "," ","█","███"y luego asigna las indicaciones de la lista a los caracteres correspondientes.

Dom Hastings
fuente
1

Haskell , 275 270 bytes

z=0:z
x!0=[]
x!n=mod n x:x!div n x
e c|Just a<-lookup c.zip"W3YZ56C$EF. 89*HM/ORU1QGNTDJ7%40LSBIP2-+XVKA".((++)<*>(reverse<$>))$take 9.(++z).(2!)<$>scanl(+)7(67!0x117CDBC49F9EEEF11C3A659CACB31236)=zipWith(\l c->c<$[1..2*l+1])(a++[0])(cycle"█ ")>>=id
f s='*':s++"*">>=e

Pruébalo en línea!

El operador x!n que calcula los dígitos de la base x de n, se usa dos veces para descomprimir los códigos. Los códigos se comprimen primero como cadenas binarias con ancho = 1 y estrecho = 0, sin importar el color, por ejemplo R↔10000110↔262. Estos números se ordenan y diferencian para obtener números en el rango [3,66], que se comprimen con el inverso del algoritmo de dígitos binarios como0x117CDBC49F9EEEF11C3A659CACB31236 . Esto contiene solo la mitad de los códigos, el resto son inversos de estos.

Sin golf:

z=0:z                       -- infinite zeroes for padding
x!0=[]                      -- digits of n in base x, recursion base case
x!n=mod n x:x!div n x       -- digits of n in base x
e c | Just a                -- read upwards from (*)
  <-lookup c                -- lookup code, given letter
  . zip"W3YZ56C$EF. 89*HM/ORU1QGNTDJ7%40LSBIP2-+XVKA" 
                            -- combine codes with correct letters
  . ((++)<*>(reverse<$>))   -- concatenate list and list with reverse codes
  $ take 9                  -- take nine
  . (++z)                   -- pad with infinite zeroes on right
  . (2!)                    -- convert to binary digits – [[1,1,1],[1,0,1,1]…]
  <$> scanl (+) 7           -- cumulative sum starting from 7 – [7,13,19,22,25…]
        (67!0x117CDBC49F9EEEF11C3A659CACB31236)       
                            -- (*) digits in base 67 – [6,6,3,3,3,9,5,7…]
  = zipWith
      (\l c->c<$[1..2*l+1]) -- combine width and color, length is 2*l+1
      (a++[0])              -- list of widths as 0/1, 0 added for interchar gap
      (cycle"█ ")           -- infinite list of bar colors, leftovers are unused
  >>=id                     -- concatenate
f s='*':s++"*">>=e          -- surround string with delimiters, map e and concat
Angs
fuente