Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
The challenge
The shortest code by character count to draw an ASCII representation of a Code 39 bar code.
Wikipedia article about Code 39: http://en.wikipedia.org/wiki/Code_39
Input
The input will be a string of legal characters for Code 39 bar codes. This means 43 characters are valid: 0-9 A-Z (space) and -.$/+%. The * character will not appear in the input as it is used as the start and stop characters.
Output
Each character encoded in Code 39 bar codes have nine elements, five bars and four spaces. Bars will be represented with # characters, and spaces will be represented with the space character. Three of the nine elements will be wide. The narrow elements will be one character wide, and the wide elements will be three characters wide. A inter-character space of a single space should be added between each character pattern. The pattern should be repeated so that the height of the bar code is eight characters high.
The start/stop character * (bWbwBwBwb) would be represented like this:
# # ### ### #
# # ### ### #
# # ### ### #
# # ### ### #
# # ### ### #
# # ### ### #
# # ### ### #
# # ### ### #
^ ^ ^^ ^ ^ ^ ^^^
| | || | | | |||
narrow bar -+ | || | | | |||
wide space ---+ || | | | |||
narrow bar -----+| | | | |||
narrow space ------+ | | | |||
wide bar --------+ | | |||
narrow space ----------+ | |||
wide bar ------------+ |||
narrow space --------------+||
narrow bar ---------------+|
inter-character space ----------------+
The start and stop character * will need to be output at the start and end of the bar code.
No quiet space will need to be included before or after the bar code.
No check digit will need to be calculated.
Full ASCII Code39 encoding is not required, just the standard 43 characters.
No text needs to be printed below the ASCII bar code representation to identify the output contents.
The character # can be replaced with another character of higher density if wanted. Using the full block character U+2588, would allow the bar code to actually scan when printed.
Test cases
Input:
ABC
Output:
# # ### ### # ### # # # ### # ### # # ### ### ### # # # # # ### ### #
# # ### ### # ### # # # ### # ### # # ### ### ### # # # # # ### ### #
# # ### ### # ### # # # ### # ### # # ### ### ### # # # # # ### ### #
# # ### ### # ### # # # ### # ### # # ### ### ### # # # # # ### ### #
# # ### ### # ### # # # ### # ### # # ### ### ### # # # # # ### ### #
# # ### ### # ### # # # ### # ### # # ### ### ### # # # # # ### ### #
# # ### ### # ### # # # ### # ### # # ### ### ### # # # # # ### ### #
# # ### ### # ### # # # ### # ### # # ### ### ### # # # # # ### ### #
Input:
1/3
Output:
# # ### ### # ### # # # ### # # # # # ### ### # # # # # ### ### #
# # ### ### # ### # # # ### # # # # # ### ### # # # # # ### ### #
# # ### ### # ### # # # ### # # # # # ### ### # # # # # ### ### #
# # ### ### # ### # # # ### # # # # # ### ### # # # # # ### ### #
# # ### ### # ### # # # ### # # # # # ### ### # # # # # ### ### #
# # ### ### # ### # # # ### # # # # # ### ### # # # # # ### ### #
# # ### ### # ### # # # ### # # # # # ### ### # # # # # ### ### #
# # ### ### # ### # # # ### # # # # # ### ### # # # # # ### ### #
Input:
- $ (minus space dollar)
Output:
# # ### ### # # # # ### ### # ### # ### # # # # # # # # ### ### #
# # ### ### # # # # ### ### # ### # ### # # # # # # # # ### ### #
# # ### ### # # # # ### ### # ### # ### # # # # # # # # ### ### #
# # ### ### # # # # ### ### # ### # ### # # # # # # # # ### ### #
# # ### ### # # # # ### ### # ### # ### # # # # # # # # ### ### #
# # ### ### # # # # ### ### # ### # ### # # # # # # # # ### ### #
# # ### ### # # # # ### ### # ### # ### # # # # # # # # ### ### #
# # ### ### # # # # ### ### # ### # ### # # # # # # # # ### ### #
Code count includes input/output (full program).
J, 102 characters
8#,:' #'{~,0,.~#:(3 u:'䝝啕啕啕䑅儑啕啕啕啕䗝䔑啕䕷煝䑑凝瑗屗眕凗瑵屵具瑝屝啕啕啕啕啕啕啕甗崗睅圗病巅呷甝崝圝畇嵇睑均痑巑嗇畱嵱坱煗䝗燕䗗煵䝵'){~32-~a.i.'*'(,,[)
Explanation. Read from the bottom up.:
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!
Ruby (1.9) - 121 132 141 166 170 289 295
Hats-off to 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'
Only stores the 44 characters required and uses Ruby's transliteration function to map these
<space>
<-> to <9>
<*>
<$>
<+>
<%>
<A> to <Z>
to the encoded values.
Python, 304 characters
No fancy Unicode compression. Only trick is to reorder the characters to maximize overlap. My first Python program.
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)
Assembler
Assembles to 220 bytes.
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:
Not much scope for doing clever tricks here.
Python 3.1, without Unicode (213 215 223 240 248 249 chars)
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)
Explanation:
The code 39 sequence is encoded into a base-4 number (left-most = least significant) with:
bw → 3
Bw → 2
bW → 1
BW → 0
The sequence is then sorted, e.g.
20333 Q
21233 N
21323 L
...
The difference of adjacent entries are taken, giving a list like [48, 12, 3, …]. Then 35 is added to this list to ensure the numbers fall in the ASCII range. This gives the "))&&&,…" string.
This code also has taken advantaged of the * will not appear in the input, so we may replace it by any invalid character, including '. In CPython repr("ABC") == "'ABC'", so we could get rid of 2 characters.
Python 3.1, with Unicode (154 158 chars)
Based on the J solution, taking advantage of the "The character # can be replaced with another character of higher density if wanted" rule, by defining density as area of dark parts divided by the smallest bounding rectangle of the glyph. :)
print((''.join(" #"[int(c)]for d in"%r"%input()for c in bin(2*ord("䝝啕啕啕䑅儑啕䗝啕啕啕䔑啕䕷煝䑑凝瑗屗眕凗瑵屵具瑝屝啕啕啕啕啕啕啕甗崗睅圗病巅呷甝崝圝畇嵇睑均痑巑嗇畱嵱坱煗䝗燕䗗煵䝵"[ord(d)-32]))[2:])+"\n")*8)
Python (2.6) -- 430 312 302 characters
Third go at the problem, still room for improvement. Character count by 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
Lua, 318 Characters
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
I don't expect to win any code-golf questions with Lua, so I don't feel bad answering my own challenge here. It was also using a different encoding I thought might be interesting to others.
Other observations
After looking closely at the encoding, it looks as if there may be a way to dispense with table look-up, and compute the bar code's encoding directly. However, I found that my attempts to build the computations took more code than the table. (This may not be the case in other languages.)
Having divided the characters into groups that indicated where the wide bars and spaces were, I saw some interesting patterns. It seems that there is only one wide space for 40 of the characters, with $/+% being exceptions (they each have three spaces.) The 40 characters being split with 10 in each slot. And, there are two wide bars for the same 40 characters. The wide bars seem to have a binary encoding with the last bar being a parity bit. The bar's bit patterns being 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 where the numbers having more then 2 bits set being avoided.
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 --> Parity
I guess it is a challenge for another day to see if the bar codes could be encoded without look-up tables.
I've done code to work with code 39 barcodes on embedded systems. There are two styles of codes, which I think of as the 39 "regular" codes and the four "oddballs". The regular codes have one of ten patterns of bar widths (two wide three narrow), and one of four patterns of space widths (one wide three narrow). The oddballs have five narrow bars and one of four patterns of bar widths (three wide one narrow). To render a barcode with compact code, convert the character into a number 0-39 (for normal codes), or 40, 50, 60, or 70 for "oddballs". Then divmod 10. The upper digit will select one of eight patterns of space widths; if the upper digit is three or less the lower digit will select one of ten patterns of bar widths. If the upper digit is 4-7, all five bars should be narrow.
The code works out very compactly using a few small lookup tables. Because lookup tables may be compactly represented as strings in source code, approaches with larger lookup tables may have shorter source code (though I think for Code Golf source code size should be counted in bytes using the most favorable coding; an approach with a string of oddball characters that would take three bytes to store in UTF-8 and two bytes for UTF-16 should either be 'charged' 3 bytes each for oddball characters, or two bytes each for all characters, whichever yields a smaller total). An approach which uses a selection of oddball characters that fit entirely within some particular single-byte code page should be charged one byte per character.
spam spam spam spam lovely spam
Related
I have search the internet in vain for a way to use Google Maps API with VueJS / NUxtJS.
I have seen many tutorial that show how it is done using this package and even vue2-google-maps.
However, despite following every single step as shown in the tutorial, I keep getting an error that looks something like this :
vue.runtime.esm.js?2b0e:619 [Vue warn]: Unknown custom element: <gmap-map> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
found in
---> <Pages/googleMaps.vue> at pages/google-maps.vue
<Nuxt>
<Default> at layouts/default.vue
<Root>
warn # vue.runtime.esm.js?2b0e:619
createElm # vue.runtime.esm.js?2b0e:5932
createChildren # vue.runtime.esm.js?2b0e:6047
createElm # vue.runtime.esm.js?2b0e:5948
patch # vue.runtime.esm.js?2b0e:6510
Vue._update # vue.runtime.esm.js?2b0e:3939
updateComponent # vue.runtime.esm.js?2b0e:4054
get # vue.runtime.esm.js?2b0e:4473
Watcher # vue.runtime.esm.js?2b0e:4462
mountComponent # vue.runtime.esm.js?2b0e:4067
Vue.$mount # vue.runtime.esm.js?2b0e:8409
init # vue.runtime.esm.js?2b0e:3118
merged # vue.runtime.esm.js?2b0e:3301
hydrate # vue.runtime.esm.js?2b0e:6372
patch # vue.runtime.esm.js?2b0e:6487
Vue._update # vue.runtime.esm.js?2b0e:3939
updateComponent # vue.runtime.esm.js?2b0e:4054
get # vue.runtime.esm.js?2b0e:4473
Watcher # vue.runtime.esm.js?2b0e:4462
mountComponent # vue.runtime.esm.js?2b0e:4067
Vue.$mount # vue.runtime.esm.js?2b0e:8409
init # vue.runtime.esm.js?2b0e:3118
hydrate # vue.runtime.esm.js?2b0e:6372
patch # vue.runtime.esm.js?2b0e:6487
Vue._update # vue.runtime.esm.js?2b0e:3939
updateComponent # vue.runtime.esm.js?2b0e:4054
get # vue.runtime.esm.js?2b0e:4473
Watcher # vue.runtime.esm.js?2b0e:4462
mountComponent # vue.runtime.esm.js?2b0e:4067
Vue.$mount # vue.runtime.esm.js?2b0e:8409
init # vue.runtime.esm.js?2b0e:3118
hydrate # vue.runtime.esm.js?2b0e:6372
hydrate # vue.runtime.esm.js?2b0e:6405
patch # vue.runtime.esm.js?2b0e:6487
Vue._update # vue.runtime.esm.js?2b0e:3939
updateComponent # vue.runtime.esm.js?2b0e:4054
get # vue.runtime.esm.js?2b0e:4473
Watcher # vue.runtime.esm.js?2b0e:4462
mountComponent # vue.runtime.esm.js?2b0e:4067
Vue.$mount # vue.runtime.esm.js?2b0e:8409
init # vue.runtime.esm.js?2b0e:3118
hydrate # vue.runtime.esm.js?2b0e:6372
hydrate # vue.runtime.esm.js?2b0e:6405
patch # vue.runtime.esm.js?2b0e:6487
Vue._update # vue.runtime.esm.js?2b0e:3939
updateComponent # vue.runtime.esm.js?2b0e:4054
get # vue.runtime.esm.js?2b0e:4473
Watcher # vue.runtime.esm.js?2b0e:4462
mountComponent # vue.runtime.esm.js?2b0e:4067
Vue.$mount # vue.runtime.esm.js?2b0e:8409
init # vue.runtime.esm.js?2b0e:3118
hydrate # vue.runtime.esm.js?2b0e:6372
hydrate # vue.runtime.esm.js?2b0e:6405
patch # vue.runtime.esm.js?2b0e:6487
Vue._update # vue.runtime.esm.js?2b0e:3939
updateComponent # vue.runtime.esm.js?2b0e:4054
get # vue.runtime.esm.js?2b0e:4473
Watcher # vue.runtime.esm.js?2b0e:4462
mountComponent # vue.runtime.esm.js?2b0e:4067
Vue.$mount # vue.runtime.esm.js?2b0e:8409
mount # client.js?06a0:689
mountApp$ # client.js?06a0:727
tryCatch # runtime.js?96cf:62
invoke # runtime.js?96cf:296
prototype.<computed> # runtime.js?96cf:114
tryCatch # runtime.js?96cf:62
invoke # runtime.js?96cf:152
eval # runtime.js?96cf:162
Promise.then (async)
invoke # runtime.js?96cf:161
eval # runtime.js?96cf:162
Promise.then (async)
invoke # runtime.js?96cf:161
eval # runtime.js?96cf:195
callInvokeWithMethodAndArg # runtime.js?96cf:194
enqueue # runtime.js?96cf:217
prototype.<computed> # runtime.js?96cf:114
runtime.async # runtime.js?96cf:241
mountApp # client.js?06a0:674
Promise.then (async)
eval # client.js?06a0:88
eval # client.js:1117
./.nuxt/client.js # app.js:35
__webpack_require__ # runtime.js:791
fn # runtime.js:151
0 # app.js:425
__webpack_require__ # runtime.js:791
checkDeferredModules # runtime.js:46
webpackJsonpCallback # runtime.js:33
(anonymous) # app.js:1
Show 38 more frames
2vue.runtime.esm.js?2b0e:619 [Vue warn]: Unknown custom element: <gmap-marker> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
found in
---> <Pages/googleMaps.vue> at pages/google-maps.vue
<Nuxt>
<Default> at layouts/default.vue
<Root>
warn # vue.runtime.esm.js?2b0e:619
createElm # vue.runtime.esm.js?2b0e:5932
createChildren # vue.runtime.esm.js?2b0e:6047
createElm # vue.runtime.esm.js?2b0e:5948
createChildren # vue.runtime.esm.js?2b0e:6047
createElm # vue.runtime.esm.js?2b0e:5948
patch # vue.runtime.esm.js?2b0e:6510
Vue._update # vue.runtime.esm.js?2b0e:3939
updateComponent # vue.runtime.esm.js?2b0e:4054
get # vue.runtime.esm.js?2b0e:4473
Watcher # vue.runtime.esm.js?2b0e:4462
mountComponent # vue.runtime.esm.js?2b0e:4067
Vue.$mount # vue.runtime.esm.js?2b0e:8409
init # vue.runtime.esm.js?2b0e:3118
merged # vue.runtime.esm.js?2b0e:3301
hydrate # vue.runtime.esm.js?2b0e:6372
patch # vue.runtime.esm.js?2b0e:6487
Vue._update # vue.runtime.esm.js?2b0e:3939
updateComponent # vue.runtime.esm.js?2b0e:4054
get # vue.runtime.esm.js?2b0e:4473
Watcher # vue.runtime.esm.js?2b0e:4462
mountComponent # vue.runtime.esm.js?2b0e:4067
Vue.$mount # vue.runtime.esm.js?2b0e:8409
init # vue.runtime.esm.js?2b0e:3118
hydrate # vue.runtime.esm.js?2b0e:6372
patch # vue.runtime.esm.js?2b0e:6487
Vue._update # vue.runtime.esm.js?2b0e:3939
updateComponent # vue.runtime.esm.js?2b0e:4054
get # vue.runtime.esm.js?2b0e:4473
Watcher # vue.runtime.esm.js?2b0e:4462
mountComponent # vue.runtime.esm.js?2b0e:4067
Vue.$mount # vue.runtime.esm.js?2b0e:8409
init # vue.runtime.esm.js?2b0e:3118
hydrate # vue.runtime.esm.js?2b0e:6372
hydrate # vue.runtime.esm.js?2b0e:6405
patch # vue.runtime.esm.js?2b0e:6487
Vue._update # vue.runtime.esm.js?2b0e:3939
updateComponent # vue.runtime.esm.js?2b0e:4054
get # vue.runtime.esm.js?2b0e:4473
Watcher # vue.runtime.esm.js?2b0e:4462
mountComponent # vue.runtime.esm.js?2b0e:4067
Vue.$mount # vue.runtime.esm.js?2b0e:8409
init # vue.runtime.esm.js?2b0e:3118
hydrate # vue.runtime.esm.js?2b0e:6372
hydrate # vue.runtime.esm.js?2b0e:6405
patch # vue.runtime.esm.js?2b0e:6487
Vue._update # vue.runtime.esm.js?2b0e:3939
updateComponent # vue.runtime.esm.js?2b0e:4054
get # vue.runtime.esm.js?2b0e:4473
Watcher # vue.runtime.esm.js?2b0e:4462
mountComponent # vue.runtime.esm.js?2b0e:4067
Vue.$mount # vue.runtime.esm.js?2b0e:8409
init # vue.runtime.esm.js?2b0e:3118
hydrate # vue.runtime.esm.js?2b0e:6372
hydrate # vue.runtime.esm.js?2b0e:6405
patch # vue.runtime.esm.js?2b0e:6487
Vue._update # vue.runtime.esm.js?2b0e:3939
updateComponent # vue.runtime.esm.js?2b0e:4054
get # vue.runtime.esm.js?2b0e:4473
Watcher # vue.runtime.esm.js?2b0e:4462
mountComponent # vue.runtime.esm.js?2b0e:4067
Vue.$mount # vue.runtime.esm.js?2b0e:8409
mount # client.js?06a0:689
mountApp$ # client.js?06a0:727
tryCatch # runtime.js?96cf:62
invoke # runtime.js?96cf:296
prototype.<computed> # runtime.js?96cf:114
tryCatch # runtime.js?96cf:62
invoke # runtime.js?96cf:152
eval # runtime.js?96cf:162
Promise.then (async)
invoke # runtime.js?96cf:161
eval # runtime.js?96cf:162
Promise.then (async)
invoke # runtime.js?96cf:161
eval # runtime.js?96cf:195
callInvokeWithMethodAndArg # runtime.js?96cf:194
enqueue # runtime.js?96cf:217
prototype.<computed> # runtime.js?96cf:114
runtime.async # runtime.js?96cf:241
mountApp # client.js?06a0:674
Promise.then (async)
eval # client.js?06a0:88
eval # client.js:1117
./.nuxt/client.js # app.js:35
__webpack_require__ # runtime.js:791
fn # runtime.js:151
0 # app.js:425
__webpack_require__ # runtime.js:791
checkDeferredModules # runtime.js:46
webpackJsonpCallback # runtime.js:33
(anonymous) # app.js:1
Show 40 more frames
client.js?e0ba:95 [HMR] connected
I once got the map to be displayed using vue2-google-maps however I was unable to manipulate the map and the object map and google where undefined.
Some help will be greatly appreciated.
Thanks.
Several times I run into mentioning that it is best to put script into proc in order to boost run time performance, e.g. this answer has the following:
That is one reason for the advices to put all your code inside procedures (they get byte-compiled that way)
Something does not click in me.
Just as described in the answer, the first time a script runs, there is a check if a command can be byte-code compiled, if it is, then it is compiled. This makes total sense. But I do not see how "proc" plays an important role. E.g. compare the following 2 scripts:
set v [concat [lindex $::argv 1] [lindex $::argv 2]]
myCmd $v
and
proc p1 {v1 v2} {
set v [concat $v1 $v2]
return [myCmd $v]
}
p1 [lindex $::argv 1] [lindex $::argv 2]
My high level interpretation of the 2 scripts tells the following:
In running either script the first time, "set", "concat", "lindex" and "return" commands are compiled
The second script also has "proc" compiled.
"myCmd" is not compiled in either script
Subsequent running of either script runs the bycode except "myCmd".
So what is the advantage of "proc"?
I did run dissamble on the scripts:
The first script:
ByteCode 0x0x83fc70, refCt 1, epoch 3, interp 0x0x81d680 (epoch 3)
Source "set v [concat [lindex $::argv 1] [lindex $::argv 2]]\nmy"
Cmds 5, src 61, inst 50, litObjs 4, aux 0, stkDepth 4, code/src 0.00
Commands 5:
1: pc 0-41, src 0-51 2: pc 2-39, src 7-50
3: pc 4-20, src 15-30 4: pc 21-37, src 34-49
5: pc 42-48, src 53-60
Command 1: "set v [concat [lindex $::argv 1] [lindex $::argv 2]]"
(0) push1 0 # "v"
Command 2: "concat [lindex $::argv 1] [lindex $::argv 2]"
(2) push1 1 # "concat"
Command 3: "lindex $::argv 1"
(4) startCommand +17 1 # next cmd at pc 21
(13) push1 2 # "::argv"
(15) loadScalarStk
(16) listIndexImm 1
Command 4: "lindex $::argv 2"
(21) startCommand +17 1 # next cmd at pc 38
(30) push1 2 # "::argv"
(32) loadScalarStk
(33) listIndexImm 2
(38) invokeStk1 3
(40) storeScalarStk
(41) pop
Command 5: "myCmd $v"
(42) push1 3 # "myCmd"
(44) push1 0 # "v"
(46) loadScalarStk
(47) invokeStk1 2
(49) done
The second script:
ByteCode 0x0xc06c80, refCt 1, epoch 3, interp 0x0xbe4680 (epoch 3)
Source "proc p1 {v1 v2} {\n set v [concat $v1 $v2]\n return"
Cmds 4, src 109, inst 50, litObjs 5, aux 0, stkDepth 4, code/src 0.00
Commands 4:
1: pc 0-10, src 0-67 2: pc 11-48, src 69-108
3: pc 13-29, src 73-88 4: pc 30-46, src 92-107
Command 1: "proc p1 {v1 v2} {\n set v [concat $v1 $v2]\n return"
(0) push1 0 # "proc"
(2) push1 1 # "p1"
(4) push1 2 # "v1 v2"
(6) push1 3 # "\n set v [concat $v1 $v2]\n return ["
(8) invokeStk1 4
(10) pop
Command 2: "p1 [lindex $::argv 1] [lindex $::argv 2]"
(11) push1 1 # "p1"
Command 3: "lindex $::argv 1"
(13) startCommand +17 1 # next cmd at pc 30
(22) push1 4 # "::argv"
(24) loadScalarStk
(25) listIndexImm 1
Command 4: "lindex $::argv 2"
(30) startCommand +17 1 # next cmd at pc 47
(39) push1 4 # "::argv"
(41) loadScalarStk
(42) listIndexImm 2
(47) invokeStk1 3
(49) done
So script 2 does have 1 less TCL command, but both scripts have 49 byte code commands.
Finally the running test, I comment out "myCmd" because I actually do not have such extension. Here is the result:
% time {source 1.tcl} 10000
242.8156 microseconds per iteration
% time {source 2.tcl} 10000
257.9389 microseconds per iteration
So the proc version is even slower.
What do I miss? Or rather, what is the exact understanding of proc and performance?
The really big reason that putting things in a procedure matters is that procedures have a local variable table. Variables in the LVT can be accessed by numerical index, which is stupendously faster than the alternative (a lookup via a hash table, even though Tcl's got an extremely fast hash table implementation). It doesn't make much difference for a one-off call, but with repeated calls or a loop, the performance differences rapidly add up to something significant. This can quite easily make the extra cost of the extra compilation and stack frame management (procedures aren't free to enter, though we try to keep them cheap) basically irrelevant in real scripts.
And yes, Tcl actually bytecode-compiles everything. It's just that it often generates sub-optimal bytecode outside of procedure(-like context)s; in the limit case for suboptimality, all the bytecode is doing is assembling arguments into a list, doing a dynamic command invoke, and routing the result.
(It's important when reading Tcl's disassembled bytecode to remember that the costs of particular bytecodes are not all the same. You cannot just count the number of instructions to work out the cost in any useful way. For example, push1 is very cheap but invokeStk1 is potentially very costly. Another example, loadScalarStk is usually much more expensive than loadScalar1; the latter is used inside procedures only.)
The following two scripts demonstrate the performance gain due to usage of procs. In the second script the internal loop is extracted into a proc, leading to a 5x speedup.
without_proc.tcl
#!/usr/bin/env tclsh
set sum 0
set n 10000
set k 100
for { set i 0 } { $i < $k } { incr i } {
set s 0
for { set j 0 } { $j < $n } { incr j } {
set s [expr {$s + $j}]
}
set sum [expr {$sum + $s}]
}
puts "sum=$sum"
with_proc.tcl
#!/usr/bin/env tclsh
proc foo {n} {
set s 0
for { set j 0 } { $j < $n } { incr j } {
set s [expr {$s + $j}]
}
return $s
}
set sum 0
set n 10000
set k 100
for { set i 0 } { $i < $k } { incr i } {
set s [foo $n]
set sum [expr {$sum + $s}]
}
puts "sum=$sum"
Benchmark:
$ tclsh
% time {source with_proc.tcl} 1
sum=4999500000
67482 microseconds per iteration
% time {source without_proc.tcl} 1
sum=4999500000
406557 microseconds per iteration
or
$ time tclsh with_proc.tcl
sum=4999500000
real 0m0.089s
user 0m0.080s
sys 0m0.004s
$ time tclsh without_proc.tcl
sum=4999500000
real 0m0.401s
user 0m0.388s
sys 0m0.016s
I have the following code which removed all OBX segments prior to the first one that contains addendum:
# This Cloverleaf TPS script removes all OBX segments prior to the first one that contains "ADDENDUM".
# This script also renumbers the OBX segments.
#
# See http://clovertech.healthvision.com/viewtopic.php?t=5953
proc remove_prior_to_addendum {args} {
# set the procedure name
# This is used for error messages
set procname [lindex [info level [info level]] 0]
# bring some common variables into the scope of this proc
global HciSite HciSiteDir HciProcessesDir HciConnName HciRootDir ibdir
# fetch mode
keylget args MODE mode
# keylget args ARGS.ARGNAME argname
switch -exact -- $mode {
start {
# Perform special init functions
# N.B.: there may or may not be a MSGID key in args
}
run {
# 'run' mode always has a MSGID; fetch and process it
keylget args MSGID msgid
# get the message
set msgdata [msgget $msgid]
# does this message have "ADDENDUM"?
if {! [regexp {OBX[^\r]*\|ADDENDUM} $msgdata] } {
# This message does not have an ADDENDUM, so continue the message
return "{CONTINUE $msgid}"
}
# if we get here, we have an ADDENDUM
# get the separators
set segment_sep \r
# process the message
if { [catch {
# commands
# split the message into segments
set segments [split $msgdata $segment_sep]
# find the first OBX with an ADDENDUM
set addendum_index [lsearch -regexp $segments {^OBX[^\r]*\|ADDENDUM}]
# renumber the OBX segments that will remain
set i 1
foreach index [lsearch -all -regexp -start $addendum_index $segments {^OBX}] {
set segment [lindex $segments $index]
set segments [lreplace $segments $index $index [regsub {^OBX\|[0-9]*\|} $segment "OBX|$i|"]]
incr i
}
# now find any OBX segments prior to the ADDENDUM segment
set obx_indexes [lsearch -all -regexp [lrange $segments 0 [expr $addendum_index - 1]] {^OBX}]
# sort the indexes descending so that we can safely remove the indexes
set obx_indexes [lsort -decreasing -integer $obx_indexes]
# remove each segment
foreach index $obx_indexes {
set segments [lreplace $segments $index $index]
}
# rebuild the message
set msgdata [join $segments $segment_sep]
} errmsg ] } {
# the commands errored
global errorInfo
msgmetaset $msgid USERDATA "ERROR: $errmsg\n*** Tcl TRACE ***\n$errorInfo"
# rethrow the error
error $errmsg $errorInfo
}
# set the output message
msgset $msgid $msgdata
# return whether to kill, continue, etc. the message
return "{CONTINUE $msgid}"
}
time {
# Timer-based processing
# N.B.: there may or may not be a MSGID key in args
}
shutdown {
# Do some clean-up work
}
default {
error "Unknown mode in $procname: $mode"
return "" ;# Dont know what to do
}
}
}
How do I edit the script so it removed ALL OBX segments from the message?
I don't know much about hl7 (in fact I know nothing about it) but it looks like you want to remove those lines:
# does this message have "ADDENDUM"?
if {! [regexp {OBX[^\r]*\|ADDENDUM} $msgdata] } {
# This message does not have an ADDENDUM, so continue the message
return "{CONTINUE $msgid}"
}
I am newbie in TCL scripting. Just wish to get some advice from experts here.
I wish to process the report with format as below. I am thinking to print the report without the header and with just single line like -
Connections for net 'pmg_ccu_ot2_tam_50mhz_sel_xainfwh' :: Driver a_par/pmg_ccu_ot2_tam_50mhz_sel_xainfwh Output Pin (a_par) :: Load b_par/pmg_ccu_ot2_tam_50mhz_sel_xainfwh Input Pin (b_par)
Connections for net 'pmg_ccu_ot2_tam_50mhz_sel_xainfwh_2' :: Driver d_par/pmg_ccu_ot2_tam_50mhz_sel_xainfwh_2 Output Pin (d_par) :: Load e_par/pmg_ccu_ot2_tam_50mhz_sel_xainfwh_2 Input Pin (e_par), f_par/pmg_ccu_ot2_tam_50mhz_sel_xainfwh_3 Input Pin (f_par)
<more . . .>
Really appreciate if anyone can give some light and idea to me. Thanks much!
****************************************
Report : net
-connections
Design : soc
Version: G-2012.06-SP2
Date : Sun Apr 7 22:56:33 2013
****************************************
Connections for net `pmg_ccu_ot2_tam_50mhz_sel_xainfwh`:
Driver Pins Type
------------ ----------------
a_par/pmg_ccu_ot2_tam_50mhz_sel_xainfwh Output Pin (a_par)
Load Pins Type
------------ ----------------
b_par/pmg_ccu_ot2_tam_50mhz_sel_xainfwh Input Pin (b_par)
1
Connections for net `pmg_ccu_ot2_tam_50mhz_sel_xainfwh_2`:
Driver Pins Type
------------ ----------------
d_par/pmg_ccu_ot2_tam_50mhz_sel_xainfwh_2 Output Pin (d_par)
Load Pins Type
------------ ----------------
e_par/pmg_ccu_ot2_tam_50mhz_sel_xainfwh_3 Input Pin (e_par)
f_par/pmg_ccu_ot2_tam_50mhz_sel_xainfwh_3 Input Pin (f_par)
1
<more . . .>
If I'm understanding your requirements correctly, I would do something like this:
Input file contains:
****************************************
Report : net
-connections
Design : soc
Version: G-2012.06-SP2
Date : Sun Apr 7 22:56:33 2013
****************************************
Connections for net `pmg_ccu_ot2_tam_50mhz_sel_xainfwh`:
Driver Pins Type
------------ ----------------
a_par/pmg_ccu_ot2_tam_50mhz_sel_xainfwh Output Pin (a_par)
Load Pins Type
------------ ----------------
b_par/pmg_ccu_ot2_tam_50mhz_sel_xainfwh Input Pin (b_par)
1
Connections for net `pmg_ccu_ot2_tam_50mhz_sel_xainfwh_2`:
Driver Pins Type
------------ ----------------
d_par/pmg_ccu_ot2_tam_50mhz_sel_xainfwh_2 Output Pin (d_par)
Load Pins Type
------------ ----------------
e_par/pmg_ccu_ot2_tam_50mhz_sel_xainfwh_3 Input Pin (e_par)
f_par/pmg_ccu_ot2_tam_50mhz_sel_xainfwh_3 Input Pin (f_par)
1
<more . . .>
The script:
# Read file containing input
set inputfile [open "inputfile.txt" r]
# File where output will be written in
set outputfile [open "outputfile.txt" w]
# $type will contain the Pin Type and $outputline will contain the final
# line to be written
set type ""
set outputline ""
# Read each line in the inputfile
while {[gets $inputfile line] != -1} {
# If first word in line is "Connections" execute
if {[lindex [split $line " "] 0] == "Connections"} {
# If $outputline not empty while in this if, it means that we have
# reached a new connection. So print out the current connection
# after joining all its elements by " :: " and reset the output line.
if {$outputline != ""} {
puts $outputfile [join $outputline " :: "]
set outputline ""
}
# Replacing the ` by ' and removing the end ":" and then putting
# the full thing into $output line as an element of a list
regsub -all {\`} $line "\'" newline
set newline [string trimright $newline "\:"]
lappend outputline $newline
}
# If there is "Pins" in the line, this means we have a header. The regexp
# captures the pin type by looking for any alphanumeric characters before
# "Pins"
regexp -- {([\w]+) Pins} $line - type
# If there is " Pin " in the line, it means we are in a row of the
# different 'Pins' type. Here, we put the while line after removing
# the extra white spaces into the $outputline list.
if {[regexp -- { Pin } $line]} {
lappend outputline "$type [string trim $line]"
}
}
# We reached the end of the document. So, add the last line into the outputfile.
puts $outputfile [join $outputline " :: "]
# Close the files we opened.
close $inputfile
close $outputfile
The output:
Connections for net 'pmg_ccu_ot2_tam_50mhz_sel_xainfwh' :: Driver a_par/pmg_ccu_ot2_tam_50mhz_sel_xainfwh Output Pin (a_par) :: Load b_par/pmg_ccu_ot2_tam_50mhz_sel_xainfwh Input Pin (b_par)
Connections for net 'pmg_ccu_ot2_tam_50mhz_sel_xainfwh_2' :: Driver d_par/pmg_ccu_ot2_tam_50mhz_sel_xainfwh_2 Output Pin (d_par) :: Load e_par/pmg_ccu_ot2_tam_50mhz_sel_xainfwh_3 Input Pin (e_par) :: Load f_par/pmg_ccu_ot2_tam_50mhz_sel_xainfwh_3 Input Pin (f_par)
This script will take 'Driver Type' or 'Load Type' in any order they come (and you can add new types as well). Are there any other possible variations in your in your input?
EDIT: You can change the switch block into this and it will take any type of Pins
if {[regexp -- {([\w]+) Pins} $line - type]} {
set counter 0
}
reEDIT: Added -- to the regexp.
rereEDIT: Matched edit in question.
This question already has answers here:
Render a string in HTML and preserve spaces and linebreaks
(7 answers)
Closed 12 months ago.
What could I do to make it print like it looks in the HTML document in the web browser?
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Example</title>
</head>
<body>
###### # # ## # # ##### # ######
# # # # # ## ## # # # #
##### ## # # # ## # # # # #####
# ## ###### # # ##### # #
# # # # # # # # # #
###### # # # # # # # ###### ######
</body>
</html>
Gives:
# # ## # # ##### # ###### # # # # # ## ## # # # # ##### ## # # # ## # # # # > ##### # ## ###### # # ##### # # # # # # # # # # # # ###### # # # # # # # ###### ######
Use the <pre> tag! Put it before and after your EXAMPLE.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Example</title>
</head>
<body>
<pre>
###### # # ## # # ##### # ######
# # # # # ## ## # # # #
##### ## # # # ## # # # # #####
# ## ###### # # ##### # #
# # # # # # # # # #
###### # # # # # # # ###### ######
</pre>
</body>
</html>
HTML is designed to collapse white space by default. In order words, all series of white spaces characters (spaces, tabs, line feeds...) are replaced by a single space on rendering. You can control this behaviour with the white-space CSS property:
The white-space CSS property is used to to describe how whitespace inside the element is handled.
Values
normal Sequences of whitespace are collapsed. Newline characters in the source are handled as other whitespace. Breaks lines as necessary to fill line boxes.
pre Sequences of whitespace are preserved, lines are only broken at newline characters in the source.
nowrap Collapses whitespace as for normal, but suppresses line breaks (text wrapping) within text.
pre-wrap Sequences of whitespace are preserved. Lines are only broken at newline characters in the source and as necessary to fill line boxes.
pre-line Sequences of whitespace are collapsed. Lines are broken at newlines in the source and as necessary to fill line boxes.
In the case ASCII art you also want to enforce a fixed-width font-family.
.ascii-art {
font-family: monospace;
white-space: pre;
}
<div class="ascii-art">
###### # # ## # # ##### # ######
# # # # # ## ## # # # #
##### ## # # # ## # # # # #####
# ## ###### # # ##### # #
# # # # # # # # # #
###### # # # # # # # ###### ######
</div>