Code 39 Barcode-Encoder

16

Schreiben Sie eine Funktion oder ein Programm, das eine Zeichenfolge in einen Barcode im Code 39- Format codiert, wobei jedes Zeichen als fünf durch vier Lücken getrennte Striche codiert wird. Entweder sind zwei der Balken und einer der Lücken breit und andere sind schmal (10 * 4 Codes), oder drei der Lücken sind breit und keiner der Balken ist (4 Codes). Dies ergibt 44 verschiedene Codes, von denen einer ein reservierter Code ist, der verwendet wird, um den Anfang und das Ende der codierten Zeichenfolge zu kennzeichnen.

Die Herausforderung

Die Eingabe ist eine Zeichenfolge, die nur Zeichen aus der Gruppe enthält

1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ-. +/$%

Die Ausgabe ist die als Barcode-Zeichenfolge codierte Zeichenfolge. Die engen Lücken und die Lücken zwischen den Zeichen sind ein einzelnes Leerzeichen und eine breite Lücke drei Leerzeichen. Der schmale Balken ist die UTF-8-Byte-Sequenz für das Unicode-Zeichen "Full Block", █, dh der 0xE2 0x96 0x88breite Balken besteht aus drei solchen Byte-Sequenzen / Zeichen ( ███). Die vollständige Liste der Codes lautet:

      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

Die Striche und Zwischenräume werden beginnend mit einem Strich verschachtelt, also ist beispielsweise Q

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

Nach der Kodierung aller Zeichen wird die Zeichenkette an beiden Enden mit begrenzt █ █ ███ ███ █. Die Zeichenlücke, ein einzelnes Leerzeichen, wird zwischen jedem Buchstaben eingefügt. Ihre Lösung gibt möglicherweise abschließende Leerzeichen und eine abschließende neue Zeile (in dieser Reihenfolge) aus.

Beispiele

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

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

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

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

Standard-Eingabe- / Ausgabeformate sind zulässig, und Standard-Lücken sind nicht zulässig. Das ist , also gewinnt der kürzeste in Bytes gemessene Code!

Angs
quelle
1
Dürfen wir anstelle von █ ein druckbares ASCII-Zeichen verwenden (Sie können das zulässige auswählen)?
Erik der Outgolfer
Was zählt für eine Sprache wie BrainFuck als "one usage"?
14 m²,
1
@Angs Ich meinte auf der Ausgabe grundsätzlich nicht im Code. Es ist nicht sehr fair, die Verwendung des #Zeichens zu bestrafen , da dies beispielsweise "#"nicht der einzige Grund ist, warum es in einer Sprache verwendet werden kann.
Erik der Outgolfer
@EriktheOutgolfer Was ich meinte, war in String-Literalen und dergleichen, aber wenn man den Punkt von l4m2 bedenkt, ist es vielleicht am besten, es zu verbieten. Gibt es denn Sprachen, die keine drei Bytes ausgeben können?
Angs

Antworten:

7

JavaScript (ES6), 225 212 Bytes

4 Bytes gespart dank @ 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]))

Probieren Sie es online!

Wie?

Die Tabelle kann so umgeordnet werden, dass die 9-Bit-Binärmaske des Zeichens anhand der folgenden Formel schnell aus Zeile und Spalte abgeleitet wird:

n = m XOR (2 << k)

mit:

  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
quelle
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)
14 m2,
@ l4m2 Das scheint nicht gültig zu sein. Es ist mir jedoch gelungen, einen Fix für 221 Bytes zu finden .
Erik der Outgolfer
@EriktheOutgolfer Ich denke, das ist im Grunde das, was l4m2 mit einem vollen Block anstelle von '#' eingereicht hat. Oder vermisse ich etwas?
Arnauld
@Arnauld Das Original ist nicht richtig eingelegt.
Erik der Outgolfer
3

Rot , 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]]

Probieren Sie es online!

Ich werde versuchen, weiter Golf zu spielen, aber ich erwarte nicht viel von dieser naiven Lösung.

Galen Ivanov
quelle
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;}

Probieren Sie es online aus.

Erläuterung:

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
quelle
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);}

Probieren Sie es online!

-8 dank ceilingcat

Verwendet die Codierungsstrategie von Arnauld. TIO Link beinhaltet-w Schalter und Boilerplate, um Warnungen zu entfernen. Diese sind unnötig und daher nicht in der Partitur enthalten.

Abgesehen von dem von Arnauld erläuterten Codierungsschema besteht der andere Trick darin, die wVariable so zu belassen, dass sie zwischen 2 und 0 wechselt ( w=2*!w). Dadurch kann ich zwischen der ersten und der zweiten Saite wählen b. Das erste ist ein Leerzeichen, das zweite ist das gefüllte Rechteck.

LambdaBeta
quelle
clever, du solltest es posten :)
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);}

Probieren Sie es online!

Basiert auf der Implementierung von @ LambdaBeta .

Etwas weniger Golf gespielt:

#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);
}
Ceilingcat
quelle
1

Kohle , 90 Bytes

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

Probieren Sie es online! Hinweis: Leerzeichen am Ende. Link ist eine ausführliche Version des Codes. Erläuterung:

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

Wickeln Sie die Eingabezeichenfolge in *s ein und ordnen Sie sie dann zweimal zu, wobei Sie das Ergebnis schließlich mit Leerzeichen verbinden. Für die zweite Map gibt es dann eine zusätzliche Map über den impliziten Bereich 0..4, in der zwei Teilzeichenfolgen verkettet werden und diese Ergebnisse dann mit der vordefinierten Konstante für leere Zeichenfolgen verknüpft werden.

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

Erstellen Sie für die erste innere Zuordnung eine Zeichenfolge, die aus den inkrementierten Ziffern, dem Großbuchstaben und den Symbolen besteht -. *+/$%, und suchen Sie die Position des zugeordneten Eingabezeichens. Zum Beispiel C++würde map to [12, 40, 40].

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

Der erste Teilstring repräsentiert die Leerzeichen vor den Balken. Vor dem ersten Balken befindet sich nichts, die anderen Balken hängen jedoch von der Position des zugeordneten Eingabezeichens ab: Wenn es über 39 liegt, enthält nur eine Stelle ein einzelnes Leerzeichen. Wenn es unter 40 liegt, enthält nur eine Stelle drei Leerzeichen, und die Position wird auch in eine Spalte umgewandelt, indem sie durch 10 geteilt wird. Wenn sich die Spalte und der Schleifenindex um 2 (Modulo 4) unterscheiden, ist dies die ungerade Stelle.

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

Der zweite Teilstring repräsentiert die Balken. Wenn die Position über 39 liegt, gibt es immer einen Balken, andernfalls wird die Position in einem Array von Bits gesucht, die Zeichen zugeordnet sind. Zum Beispiel, wenn die Position 12 ist, dann ist das kreisförmig auf das Zeichen indiziert ', das ist 100111binär, was darauf hindeutet breite Balken in den Spalten 1 und 2. (Die führende 1ignoriert wird , sondern sorgt lediglich eine konsistente Bitzahl.)

Neil
quelle
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{''}

Probieren Sie es online!

Enthält viele nicht druckbare und High-Byte-Zeichen, TIO-Link bietet eine xxdDarstellung. Ich hatte gehofft, dass dies kleiner geworden wäre, und ich könnte die Daten immer noch effizienter packen, damit ich sehen kann, wie es mir geht. Dies baut alle Permutationen von auf " "," ","█","███"und ordnet dann die Angaben der Liste den entsprechenden Zeichen zu.

Dom Hastings
quelle
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

Probieren Sie es online!

Der Operator x!n, der die x-Basis-Ziffern von n berechnet, wird zweimal zum Dekomprimieren der Codes verwendet. Die Codes werden zuerst als binäre Zeichenketten mit wide = 1 und narrow = 0 komprimiert, ohne Rücksicht auf die Farbe, z R↔10000110↔262. Diese Zahlen werden dann sortiert und differenziert, um Zahlen im Bereich [3,66] zu erhalten, die mit der Umkehrung des binären Ziffernalgorithmus wie folgt komprimiert werden0x117CDBC49F9EEEF11C3A659CACB31236 . Dies enthält nur die Hälfte der Codes, der Rest sind Umkehrungen davon.

Ungolfed:

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
quelle