Mites tuo pankkiviivakoodin (Code128 C) tarkiste tehdään, eli sen laskemiseenhan käytetään Modulo 103-algoritmia.
Eli jos viivakoodin sisältö on:
[105]579440520200360820048831509000000868516259619897100612[74][stop]
niin tuo 74 on se tarkiste ja tuo stop on loppumerkki.
Tämän oppaan ohjeet siihen ovat:
Pankkiviivakoodi-opas.pdf kirjoitti:
Tarkiste lasketaan Modulo 103 -algoritmin mukaisesti symbolin
kaikkien merkkien (siis myös alkumerkin)
perusteella lukuun ottamatta loppumerkkiä seuraavasti:
1. Alkumerkki saa arvon 105.
2. Symbolin jokaiselle merkille (arvoparille) annetaan painoarvo.
Alkumerkki saa painon 1. Sen jälkeen ensimmäinen arvopari saa painon 1, toinen
painon 2, kolmas painon 3 jne. aina painoarvoon 27 asti.
Huom! Sekä alkumerkki että ensimmäinen arvopari saavat painoarvon 1.
3. Jokainen arvopari kerrotaan painollaan ja näin saadut tulot lasketaan yhteen.
4. Yhteissumma jaetaan luvulla 103.
5. Kohdan 3 jakolaskun jakojäännös on tarkisteen arvo.
Miten tämä toteutetaan pythonilla?
Code128-viivakoodin Code C:
def Code128_C(data): s = str(data) for i in s: if i not in "0123456789": raise ValueError("Code128_C can only contain numeric data!") if len(s) % 2 != 0: raise ValueError("Code128_C needs an even number of digits.") t = [int(s[i:i+2]) for i in range(0, len(s), 2)] x = 105 + sum(t[i] * (i+1) for i in range(len(t))) return [105] + t + [x % 103, 106]
Käyttöesimerkki:
s = "579440520200360820048831509000000868516259619897100612" t = Code128_C(s) print(t) # [105, 57, 94, 40, 52, 2, 0, 36, 8, 20, 4, 88, 31, 50, 90, 0, 0, 8, 68, 51, 62, 59, 61, 98, 97, 10, 6, 12, 74, 106] print(" ".join("%02d" % i for i in t)) # 105 57 94 40 52 02 00 36 08 20 04 88 31 50 90 00 00 08 68 51 62 59 61 98 97 10 06 12 74 106
Kiitos Metabolix.
Merkkijonon koostumisen pelkästään numeroista voi tarkistaa myös näin:
if not s.isnumeric(): raise ValueError("Code128_C can only contain numeric data!")
Chiman kirjoitti:
(10.11.2015 10:14:23): Merkkijonon koostumisen pelkästään numeroista...
Eipäs tässä tapauksessa. Esimerkiksi ⅕ ei kelpaa CODE128_C koodiin.
Itse asiassa tuo Pythonin isnumeric tuntuu äkkiseltään turhakkeelta kun "32⅕45" on numeerinen mutta vaikkapa "3,141" tai "3.141" ei.
Grez kirjoitti:
Eipäs tässä tapauksessa. Esimerkiksi ⅕ ei kelpaa CODE128_C koodiin.
Näinpä onkin. isnumericin docstring ei vihjaissut tuosta mitään. Pythonin varsinaisessa dokumentaatiossa tuo kerrotaan.
Sitten tekisin näin:
if any(c not in "0123456789" for c in s): raise ValueError("Code128_C can only contain numeric data!")
Grez kirjoitti:
Sitten tekisin näin:
if any(c not in "0123456789" for c in s): raise ValueError("Code128_C can only contain numeric data!")
Eli laitanko koodin tähän muotoon:
def Code128_C(data): s = str(data) if any(c not in "0123456789" for c in s): raise ValueError("Code128_C can only contain numeric data!") if len(s) % 2 != 0: raise ValueError("Code128_C needs an even number of digits.") t = [int(s[i:i+2]) for i in range(0, len(s), 2)] x = 105 + sum(t[i] * (i+1) for i in range(len(t))) return [105] + t + [x % 103, 106] s = "579440520200360820048831509000000868516259619897100612" t = Code128_C(s) print(t) # [105, 57, 94, 40, 52, 2, 0, 36, 8, 20, 4, 88, 31, 50, 90, 0, 0, 8, 68, 51, 62, 59, 61, 98, 97, 10, 6, 12, 74, 106] print(" ".join("%02d" % i for i in t)) # 105 57 94 40 52 02 00 36 08 20 04 88 31 50 90 00 00 08 68 51 62 59 61 98 97 10 06 12 74 106
Kyllä, voit muuttaa koodia noin, jos haluat. Chimanin neuvo ei sinänsä toiminnallisesti paranna koodia, vaan kyseessä on lähinnä tyyliseikka. (Itse käytän Pythonia niin vähän, että en aina keksi tuollaisia mahdollisuuksia.)
Selvä, pääasiahan on se, että ohjelmakoodi toimii kuten pitää.
Metabolix kirjoitti:
Chimanin neuvo ei sinänsä toiminnallisesti paranna koodia, vaan kyseessä on lähinnä tyyliseikka. (Itse käytän Pythonia niin vähän, että en aina keksi tuollaisia mahdollisuuksia.)
Koodisi oli muuten niin osuva, että tuo mainittu kohta houkutti parantamiseen. Ironisesti tilalle ensin tarjoamani koodi olikin toiminnallisesti huonompi. Hyvä että Grez korjasi.
Muuten, isnumericin sijasta merkkijonon isdigit-metodi hoitanee homman oikein. Tuon poikkeustekstin numeric-sana altisti näköjään ajatusvirheelle.
>>> [x for x in ('', 'a', '4a', '½', '-2', '7.0', '5', '007', '1e4', '0x21') if x.isdigit()] ['5', '007']
Lisäys: myös '½' mukaan testiin.
Aihe on jo aika vanha, joten et voi enää vastata siihen.