Code Golf: Code 39 条形码

26

挑战

以字符数量最少的代码绘制 Code 39 条形码的 ASCII 表示。

Code 39 的维基百科文章: http://en.wikipedia.org/wiki/Code_39

输入

输入将是一个字符串,其中包含用于 Code 39 条形码的合法字符。这意味着有 43 个字符是有效的:0-9A-Z、空格和-.$/+%。输入中不会出现 * 字符,因为它用作起始和终止字符。

输出

Code 39 条形码中每个编码字符都有九个元素,五个条和四个空格。条将由字符 # 表示,空格将由空格字符表示。其中三个元素是宽度为三个字符的宽元素,其余为宽度为一个字符的窄元素。应在每个字符模式之间添加一个单空格的字符间隔。该模式应重复,以使条形码的高度为八个字符高。

起始/停止字符 * (bWbwBwBwb)应表示为:

                       #   # ### ### # 
                       #   # ### ### # 
                       #   # ### ### # 
                       #   # ### ### # 
                       #   # ### ### # 
                       #   # ### ### # 
                       #   # ### ### # 
                       #   # ### ### # 
                       ^ ^ ^^ ^ ^ ^ ^^^
                       | | || | | | |||
           narrow bar -+ | || | | | |||
           wide space ---+ || | | | |||
           narrow bar -----+| | | | |||
         narrow space ------+ | | | |||
             wide bar --------+ | | |||
         narrow space ----------+ | |||
             wide bar ------------+ |||
         narrow space --------------+||
           narrow bar ---------------+|
inter-character space ----------------+
  • 在条形码的开头和结尾需要输出字符 *
  • 条形码前后不需要包含静态空间。
  • 无需计算校验位。
  • 仅需要标准的43个字符,不需要完整的ASCII Code39编码。
  • 不需要在ASCII条形码表示下方打印文本以标识输出内容。
  • 如果需要,可以用更高密度的另一个字符替换字符 #。使用全块字符U+2588可使条形码在打印时实际扫描。

测试案例

Input:
ABC
Output:
#   # ### ### # ### # #   # ### # ### #   # ### ### ### #   # # #   # ### ### # 
#   # ### ### # ### # #   # ### # ### #   # ### ### ### #   # # #   # ### ### # 
#   # ### ### # ### # #   # ### # ### #   # ### ### ### #   # # #   # ### ### # 
#   # ### ### # ### # #   # ### # ### #   # ### ### ### #   # # #   # ### ### # 
#   # ### ### # ### # #   # ### # ### #   # ### ### ### #   # # #   # ### ### # 
#   # ### ### # ### # #   # ### # ### #   # ### ### ### #   # # #   # ### ### # 
#   # ### ### # ### # #   # ### # ### #   # ### ### ### #   # # #   # ### ### # 
#   # ### ### # ### # #   # ### # ### #   # ### ### ### #   # # #   # ### ### # 

Input:
1/3
Output:
#   # ### ### # ### #   # # ### #   #   # #   # ### ###   # # # #   # ### ### # 
#   # ### ### # ### #   # # ### #   #   # #   # ### ###   # # # #   # ### ### # 
#   # ### ### # ### #   # # ### #   #   # #   # ### ###   # # # #   # ### ### # 
#   # ### ### # ### #   # # ### #   #   # #   # ### ###   # # # #   # ### ### # 
#   # ### ### # ### #   # # ### #   #   # #   # ### ###   # # # #   # ### ### # 
#   # ### ### # ### #   # # ### #   #   # #   # ### ###   # # # #   # ### ### # 
#   # ### ### # ### #   # # ### #   #   # #   # ### ###   # # # #   # ### ### # 
#   # ### ### # ### #   # # ### #   #   # #   # ### ###   # # # #   # ### ### # 

Input:
- $     (minus space dollar)
Output:
#   # ### ### # #   # # ### ### #   ### # ### # #   #   #   # # #   # ### ### # 
#   # ### ### # #   # # ### ### #   ### # ### # #   #   #   # # #   # ### ### # 
#   # ### ### # #   # # ### ### #   ### # ### # #   #   #   # # #   # ### ### # 
#   # ### ### # #   # # ### ### #   ### # ### # #   #   #   # # #   # ### ### # 
#   # ### ### # #   # # ### ### #   ### # ### # #   #   #   # # #   # ### ### # 
#   # ### ### # #   # # ### ### #   ### # ### # #   #   #   # # #   # ### ### # 
#   # ### ### # #   # # ### ### #   ### # ### # #   #   #   # # #   # ### ### # 
#   # ### ### # #   # # ### ### #   ### # ### # #   #   #   # # #   # ### ### # 

代码计数包括输入/输出(完整程序)。


@Dav - 你说不理想:我说这是挑战的一部分。查找表也可以被压缩。 - gwell
然而,由于声明字面量的语法不同,表格很可能会在不同语言之间引起较大的差异。 - Amber
@Dav,这就是他们对于莫尔斯电码代码高尔夫比赛所说的话。https://dev59.com/DHM_5IYBdhLWcg3wgjW2 - John La Rooy
我可能会说同样的话,你想表达什么? - Amber
4
@Dav,“morse code”这篇文章在该网站上获得了41个赞和31个回答,排名相当不错。 - John La Rooy
显示剩余2条评论
10个回答

25

J,102个字符

8#,:' #'{~,0,.~#:(3 u:'䝝啕啕啕䑅儑啕啕啕啕䗝䔑啕䕷煝䑑凝瑗屗眕凗瑵屵具瑝屝啕啕啕啕啕啕啕甗崗睅圗病巅呷甝崝圝畇嵇睑均痑巑嗇畱嵱坱煗䝗燕䗗煵䝵'){~32-~a.i.'*'(,,[)

解释。从底部往上读:

8#,:         NB. Copy 8 times
' #'{~       NB. Turn binary 0 and 1 into space and #
,            NB. Link the array into a list
0,.~         NB. Append a 0 to the end of each row of the array.
#:           NB. Turn the list of numbers into a binary array where each row is the base-2 representation of the corresponding number
(3 u:'䝝啕啕啕䑅儑啕啕啕啕䗝䔑啕䕷煝䑑凝瑗屗眕凗瑵屵具瑝屝啕啕啕啕啕啕啕甗崗睅圗病巅呷甝崝圝畇嵇睑均痑巑嗇畱嵱坱煗䝗燕䗗煵䝵') NB. Turn this wchar string into a list of ints in range 0-65535.
{~           NB. Select numbers from the string-list whose indices are...
32-~         NB. ... 32 less than ...
a.i.         NB. ... the ascii values of ...
'*'(,,[)     NB. ... the input string with a '*' on either side!

8

Ruby (1.9) - 121 132 141 166 170 289 295

致敬David

puts"*#{$_}*
".tr(" --9*$+%A-Z","䝝䕷煝䑑凝瑗屗眕凗瑵屵具瑝屝䗝䑅䔑儑甗崗睅圗病巅呷甝崝圝畇嵇睑均痑巑嗇畱嵱坱煗䝗燕䗗煵䝵").gsub(/./){|c|c.ord.to_s(2).tr"01"," #"}*8


echo "ABC" | ruby -ne 'puts"*#{$_}*
".tr(" --9*$+%A-Z","䝝䕷煝䑑凝瑗屗眕凗瑵屵具瑝屝䗝䑅䔑儑甗崗睅圗病巅呷甝崝圝畇嵇睑均痑巑嗇畱嵱坱煗䝗燕䗗煵䝵").gsub(/./){|c|c.ord.to_s(2).tr"01"," #"}*8'

仅存储所需的44个字符,并使用Ruby的音译功能将其映射

<space>
<-> to <9>
<*>
<$>
<+>
<%>
<A> to <Z>

转换成编码值。


你能通过内联m来删减一些字符吗? - Dykam
那节省了4个字符。谢谢@Dykam :) - Anurag
我非常确定 * 字符不是输入的一部分 - 你必须在代码中添加它们。 - David
@David,代码中正在添加星号字符 - puts"*#{$_}*\n" - Anurag
当然,你是对的。我应该在喝咖啡之前停止尝试阅读压缩的 Ruby 代码。 :) - David

7

Python, 304个字符

没有花哨的Unicode压缩。唯一的技巧是重新排列字符以最大化重叠。这是我的第一个Python程序。

b="BWbwbwBwbWBwbwbwBWbwBwbwbWBwbwBwbWbwBwbwBWbwbwBWBwbwbwbWBwBwbwbWbwBwBwbWbwbwBwBWbwbwbwBWBwbWbWbWbwbWbWbWb"
s=t=""
for x in"*"+raw_input()+"*":
 i=".NI5VRD9YLH4 OB8XSE2?J6WKG0ZMA7*PC1-TF3UQ????$/+%".find(x)*2
 s+=b[i:i+9]+"w"
for x in s:t+=["#"," ","###","   "]["bwBW".find(x)]
for k in b[-8:]:print(t)

12
你的第一个Python程序是一款"代码高尔夫"游戏。你一定在开玩笑吧。 - Earlz
1
解释了为什么我之前不知道在后来的Python中可以使用print(t + "\n")*8或input(),以及其他我现在正在学习的东西。 - xan

6

汇编语言

汇编成220个字节。

    mov di,ds
    mov al,42
    call a3
    mov dh,[80h]
    mov si,82h
 a1:lodsb
    call a3
    dec dh
    jnz a1
    mov al,42
    call a3
    mov ax,2573
    stosw
    mov al,36
    stosb
    mov cl,8
 a2:mov dx,ds
    mov ah,9
    int 21h
    loop a2
 a3:sub al,97
    cmp al,26
    ja a4
    sub al,32
 a4:mov bx,a6-3
 a8:add bx,3
    cmp bx,a7
    jae ret
    cmp al,[bx]
    jne a8
    mov bp,[bx+1]
 a5:rcr bp,1
    mov al,36
    sbb al,0
    and al,35
    stosb
    or bp,bp
    jnz a5
    mov al,32
    stosb
    ret
 a6:dd 0D05DC5CFh,01DD17517h,05477D275h,0D475C5D3h,01DD55717h,07745D657h,0D85D17D7h,057E05D1Dh
    dd 0745DE174h,0E35177E2h,0D7E47475h,051DDE551h,0E77715E6h,05DE85C57h,05C75E95Ch,0EB7157EAh
    dd 077EC715Dh,07175ED45h,0EF45D7EEh,0D5F045DDh,04757F171h,0F3475DF2h,047F44775h,07571F575h
    dd 0F755C7F6h,047F875D1h,05771F957h,0CD7751CCh,071BF5D47h,05111C35Dh,0CA4511CEh,045C44451h
    dd 05DD1C944h
 a7:

这里没有太多的机会来做聪明的技巧。


有很多巧妙技巧的空间。将代码分为三组:' '-'0','1'-'9'和'A'-'Z'。使用17个字符的转换表将第一组映射到各种数字9-39、40、50、60和70;将第二组映射到0-8,将第三组映射到10-35。使用AAM将数字分成两部分(0-7和0-9),然后使用8字节查找表和10字节查找表获取条和空格的模式,但对于代码40-70,所有五个条都应该是窄的。可能可以在约100个字节内完成。 - supercat

5

Python 3.1,不带Unicode(213 215 223 240 248 249个字符)

本文介绍的是不包含Unicode的Python 3.1版本,共有213个字符(之前版本有215、223、240、248和249个字符)。
o=""
for c in"%r"%input():
 u="W3YZ56C$EF. 89'0HIJM/OP+%RSTUV12X4ABD-7GKLNQ".find(c);n=sum(b"))&&&,(*&2&&&)),&/8(*&1)<&/V&&&)),&/5);D&/S"[u:])-930+35*u
 while n:o+="###"[n%2*2:]+"   "[n&2:];n>>=2
print((o+"\n")*8)

说明:

Code 39序列被编码为一个基于4的数字(最左边是最不重要的),其中:

  • bw → 3
  • Bw → 2
  • bW → 1
  • BW → 0

然后对序列进行排序,例如:

20333   Q
21233   N
21323   L
...

相邻条目的差被取出,形成一个类似于[48, 12, 3, …]的列表。然后将35添加到该列表中,以确保数字落在ASCII范围内。这给出了字符串"))&&&,…"
此代码还利用了*不会出现在输入中的优势,因此我们可以将其替换为任何无效字符,包括'。在CPython中,repr("ABC") == "'ABC'",因此我们可以摆脱2个字符。

3

Python 3.1, 带有Unicode支持(154个字符)

基于J解决方案,利用"如果需要,字符#可以被另一个更高密度的字符替换"规则,通过将密度定义为暗部分面积除以字形的最小外接矩形。 :)

print((''.join(" #"[int(c)]for d in"%r"%input()for c in bin(2*ord("䝝啕啕啕䑅儑啕䗝啕啕啕䔑啕䕷煝䑑凝瑗屗眕凗瑵屵具瑝屝啕啕啕啕啕啕啕甗崗睅圗病巅呷甝崝圝畇嵇睑均痑巑嗇畱嵱坱煗䝗燕䗗煵䝵"[ord(d)-32]))[2:])+"\n")*8)

2

Python (2.6) -- 430 312 302个字符

第三次尝试解决问题,仍有改进的空间。字符计数使用wc -m

#coding:UTF8
k=""
for c in"*%s*"%raw_input():
 i=" $*.02468BDFHJLNPRTVXZ%+-/13579ACEGIKMOQSUWY".find(c)*2
 for j in"%05d%s"%tuple(map(ord,u"ಊҺ௖ூ௄Һ姢ҺЈҺӎϴЈϴӐϲ刦ҺҺ௄ϴ௄Ҽூ划ಊϴಊҺЈϴЈҼІ划ӎϴӎಊϴ௄ϴಌϲІ௖ூ௖ூҼ௖І刦ϴ勮ϲ刨ϲІҼӎҺ划௄勚ூ刔ூϲಌҺಊ划Ј勚І刔ІϲӐҺӎ姢ϴ媪ϲ姤ϲ"[i:i+2])):k+=["#"," ","###","   "][int(j)]
 k+=" "
exec"print k;"*8

2
这只是数据打包(目前也不是很好)。在代码高尔夫比赛中,我会觉得这是可以接受的。 - ChristopheD

1

Lua,318个字符

z={"1358ACEHKMORUWY.","UVWXYZ-. $/+*","2369BCFILMPSVWZ ","0123456789$/%","0456DEFJNOPTXYZ*","ABCDEFGHIJ$+%","0789GHIJQRST-. *","KLMNOPQRST/+%","1247ABDGKLNQUVX-",""}i="*"..(...).."*"o=""for c in i:gfind(".")do for j=1,10 do o=o..((j%2==0 and" "or"#"):rep(z[j]:find(c,1,true)and 3 or 1))end end for j=1,8 do print(o)end

我不指望用 Lua 赢得任何代码高尔夫问题,所以我不会感到难过在这里回答自己的挑战。而且它使用了一种不同的编码,我认为可能会对其他人有趣。

其他观察结果

经过仔细观察编码后,看起来可能有一种方法可以省去表查找,并直接计算条形码的编码。但是,我发现构建计算所需的代码比表格多。(在其他语言中可能不是这种情况。)

将字符分组到指示宽条和空格位置的组中后,我看到了一些有趣的模式。似乎只有 40 个字符有一个宽空格,$/+% 是例外(它们每个都有三个空格)。这 40 个字符被分成每个槽中的 10 个。并且,相同的 40 个字符有两个宽条。宽条似乎具有二进制编码,最后一条是奇偶校验位。 条的位模式为 1、2、3、4、5、6、8、9、10、12,其中避免设置超过 2 位的数字。

1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ-._*
1 3 5  8  A C E  H  K M O  R  U W Y  .   1010100100
 23  6  9  BC  F  I  LM  P  S  VW  Z  _  0110010010
   456   0   DEF   J   NOP   T   XYZ   * 0001110001
      7890      GHIJ      QRST      -._* 0000001111
12 4  7   AB D  G   KL N  Q   UV X  -    1101001000 --> 奇偶校验

我猜不使用查找表来编码条形码可能是另一天的挑战。


0
我已经编写了与嵌入式系统上的代码39条形码配合使用的代码。这里有两种样式的代码,我将其视为39个“常规”代码和四个“奇怪”的代码。常规代码具有十种条宽度模式(两个宽的三个窄的),以及四种空间宽度模式(一个宽的三个窄的)。奇怪的代码有五个窄条和四种条宽度模式之一(三个宽的一个窄的)。为了使用紧凑的代码呈现条形码,请将字符转换为0-39的数字(用于正常代码),或40、50、60或70(用于“奇怪的”代码)。然后进行divmod 10运算。上位数字将选择八种空间宽度模式;如果上位数字小于等于3,则下位数字将选择十种条宽度模式之一。如果上位数字为4-7,则所有五个条都应该是窄的。

使用一些小的查找表,代码可以非常紧凑地工作。因为查找表可以在源代码中被紧凑地表示为字符串,所以使用更大的查找表的方法可能会有更短的源代码(尽管我认为对于 Code Golf 来说,应该使用最有利的编码方式按字节计算源代码大小;使用一串奇怪字符的方法,在 UTF-8 中需要三个字节来存储,在 UTF-16 中需要两个字节,应该对每个奇怪字符“收费”3个字节,或者对所有字符每个收费2个字节,以得到更小的总数)。使用一些完全适合某个特定单字节代码页的奇怪字符的方法,应该对每个字符收取一个字节的费用。


-1

垃圾邮件,垃圾邮件,垃圾邮件,美好的垃圾邮件


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接