Warum piept die Kasse, wenn jemand eine Ziffer eines Strichcodes falsch eintippt? Du rechnest eine Prüfziffer von Hand aus, liest Struktogramme und übersetzt sie in Code. Dann planst du selbst, mit Kommentaren im Code, bevor du programmierst, und findest heraus, welche Tippfehler die Kasse übersieht.
Samstagvormittag im Supermarkt. Auf einer Packung Nudeln ist der Strichcode zerknittert, und der Scanner piept nicht. Die Kassiererin tippt die dreizehn Ziffern unter den Strichen von Hand ein:
Dreizehn Ziffern sind viele, und beim Abtippen passiert schnell ein Fehler. Dann stünde auf dem Kassenbon eine andere Ware mit einem anderen Preis.
Die Kassiererin tippt statt der dritten Ziffer eine andere ein, sonst stimmt alles. Was macht die Kasse?
Der Code heißt EAN-13 (European Article Number, heute GTIN-13); er steht auf fast jeder Ware im Laden. Die ersten zwölf Ziffern sagen, aus welchem Land die Nummer kommt, welche Firma sie vergeben hat und welche Ware es ist. Die dreizehnte ist keine Information über die Ware, sondern eine Prüfziffer: Sie wird aus den anderen zwölf berechnet, nach einer Regel, die die Organisation GS1 festgelegt hat:
Für die Ziffern 4 001234 56789 sieht das so aus:
| Ziffer | 4 | 0 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Gewicht | 1 | 3 | 1 | 3 | 1 | 3 | 1 | 3 | 1 | 3 | 1 | 3 |
| Produkt | 4 | 0 | 0 | 3 | 2 | 9 | 4 | 15 | 6 | 21 | 8 | 27 |
Die Summe ist 99; bis 100 fehlt 1, also ist der ganze Code 4 001234 567891.
Berechne die Prüfziffer zu den ersten zwölf Ziffern 4 260111 02043,
von Hand oder mit dem Taschenrechner.
Schreib die zwölf Ziffern untereinander und daneben abwechselnd 1 und 3, mit 1 beginnend. Multipliziere jede Ziffer mit ihrem Gewicht.
Die Produkte sind 4, 6, 6, 0, 1, 3, 1, 0, 2, 0, 4, 9.
Hier geht es weiter, sobald du deine Antwort oben abgegeben hast.
Die Kasse rechnet genauso, mit den zwölf Ziffern, die eingetippt wurden. Passt das Ergebnis nicht zur dreizehnten Ziffer, piept sie.
Und warum merkt sie jede einzelne falsche Ziffer? Ändert sich eine Ziffer mit dem Gewicht 1 um 1 bis 9, ändert sich die Summe um 1 bis 9. Ändert sich eine mit dem Gewicht 3, ändert sich die Summe um 3, 6, 9, …, 27, aber nie um 10, 20 oder 30. In beiden Fällen ist danach eine andere Prüfziffer nötig.
Der Scanner liest keine Ziffern, sondern hell und dunkel. Ein Strichcode ist in 95 gleich breite Streifen geteilt, die Module. Jedes Modul ist dunkel oder hell, also eine 1 oder eine 0; ein breiter Strich sind mehrere dunkle Module nebeneinander.

Am Rand und in der Mitte stehen feste Muster: 101 links und rechts, 01010
in der Mitte. Ihre Striche reichen weiter nach unten als die anderen. An ihnen
erkennt der Scanner, wo der Code anfängt, wo seine Mitte ist und wie breit ein
Modul ist, egal wie weit die Packung vom Scanner entfernt ist. Dazwischen
stehen links und rechts je sechs Ziffern mit je sieben Modulen.
Jede Ziffer besteht aus genau zwei dunklen und zwei hellen Abschnitten. Welches Muster zu welcher Ziffer gehört, legt GS1 in einer Tabelle fest, und zwar in drei Fassungen, L, G und R. So sieht die 4 in allen dreien aus:

R ist L mit vertauschtem Hell und Dunkel, G ist R von hinten nach vorne gelesen. Darum genügt die Tabelle für L:
| Ziffer | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|---|---|---|---|---|---|---|---|---|---|---|
| L | 0001101 |
0011001 |
0010011 |
0111101 |
0100011 |
0110001 |
0101111 |
0111011 |
0110111 |
0001011 |
Rechts von der Mitte steht jede Ziffer in R. Links steht sie in L oder in G, und L hat immer eine ungerade Zahl dunkler Module, G eine gerade.
Rechts von der Mitte steht eine Ziffer mit dem Muster 1000010. Welche
Ziffer ist es?
Rechts steht jede Ziffer in R, und R ist L mit vertauschtem Hell und Dunkel.
Aus 1000010 wird mit vertauschten 0 und 1 0111101.
Zähl die Ziffern unter dem Code: Links und rechts von der Mitte stehen je sechs, die 4 ganz vorne hat keine eigenen Striche. Sie steckt in der Auswahl der Fassungen in der linken Hälfte. Bei den Nudeln stehen die Ziffern 2 6 0 1 1 1 in den Fassungen L G L L G G, und dieses Muster bedeutet die 4:
| Erste Ziffer | Linke Hälfte |
|---|---|
| 0 | L L L L L L |
| 1 | L L G L G G |
| 2 | L L G G L G |
| 3 | L L G G G L |
| 4 | L G L L G G |
| 5 | L G G L L G |
| 6 | L G G G L L |
| 7 | L G L G L G |
| 8 | L G L G G L |
| 9 | L G G L G L |
Die erste Ziffer links steht dabei immer in L. Liest der Scanner einen Code von rechts nach links, etwa weil die Packung auf dem Kopf liegt, trifft er zuerst auf eine Ziffer mit einer geraden Zahl dunkler Module. Daran merkt er, dass er rückwärts liest, und dreht die Ziffern um.
Auf einer anderen Ware stehen die sechs Ziffern links von der Mitte in den Fassungen L G G L L G. Mit welcher Ziffer beginnt ihr Code?
Die erste Ziffer hat keine eigenen Striche; sie steckt im Muster der Fassungen links.
Such das Muster L G G L L G in der Tabelle der ersten Ziffern.
Die Regel in Worten ist kurz, aber ein Computer braucht es genauer: Wo fängt das Zählen an? Was heißt »bis zur nächsten durch 10 teilbaren Zahl«? Bevor du programmierst, schreibst du einen Algorithmus darum so auf, dass er genau ist und trotzdem in keiner Programmiersprache: als Pseudocode oder als Struktogramm. Beides steht im Handbuch unter Pseudocode und Struktogramme, mit einem Feld zum Ausprobieren.
Ein Struktogramm liest man von oben nach unten. Jeder Kasten ist eine
Anweisung; eine Schleife hat links einen Balken, und was rechts daneben steht,
wiederholt sie, solange ihre Bedingung oben wahr ist. n mod 10 ist der Rest
bei der Division durch 10, n div 10 das ganzzahlige Ergebnis.
mystery(n): s ← 0 while n > 0: s ← s + n mod 10 n ← n div 10 return s
Was gibt mystery(4021) zurück? Geh das Struktogramm Zeile für Zeile
durch und schreib dir die Werte von n und s auf.
Hier geht es weiter, sobald du deine Antwort oben abgegeben hast.
n mod 10 ist die letzte Ziffer von n, und n div 10 streicht sie: Aus 4021
wird 402, dann 40, dann 4, dann 0. mystery addiert also alle Ziffern, das ist
die Quersumme. Mit mod und div kommt man an die Ziffern einer Zahl, und
mit mod sagt man, was übrig bleibt, wenn eine Zahl nicht aufgeht.
So sieht die Regel von GS1 als Struktogramm aus. digits ist eine Liste der
zwölf Ziffern; die erste hat den Index 0. weight(i) ist das Gewicht der
Ziffer mit dem Index i, also 1 oder 3.
check_digit(digits): total ← 0 for i from 0 to 11: total ← total + weight(i) * digits[i] return (10 - total mod 10) mod 10
total mod 10 ist der Rest, und 10 - total mod 10 ist, was bis zur nächsten
durch 10 teilbaren Zahl fehlt.
Die Prüfziffer ist (10 - total mod 10) mod 10. Wann ändert das zweite
mod 10 etwas am Ergebnis?
Lege im Workspace einen Ordner und darin eine Datei für die Funktionen an:
mkdir -p ~/check-digits cd ~/check-digits touch check_digits.rb
Öffne check_digits.rb im Editor. Ausprobieren kannst du deine Funktionen in
irb, das die Datei vorher lädt:
irb -r ./check_digits.rb
Dort tippst du einen Aufruf wie weight(3) und siehst, was er zurückgibt. Nach
einer Änderung an der Datei beendest du irb mit StrgD
und startest es neu.
Lege im Workspace einen Ordner und darin eine Datei für die Funktionen an:
mkdir -p ~/check-digits cd ~/check-digits touch check_digits.py
Öffne check_digits.py im Editor. Ausprobieren kannst du deine Funktionen in
Python selbst, das die Datei vorher ausführt:
python3 -i check_digits.py
Dort tippst du einen Aufruf wie weight(3) und siehst, was er zurückgibt. Nach
einer Änderung an der Datei beendest du Python mit StrgD
und startest es neu.
Die Ziffern mit geradem Index (0, 2, 4, …) haben das Gewicht 1, die mit ungeradem Index das Gewicht 3.
weight(index),
die für einen Index das Gewicht zurückgibt.
Ob eine Zahl gerade ist, sagt der Rest bei der Division durch 2: index % 2
ist 0 oder 1. Ruby hat dafür auch index.even?.
Als Struktogramm ist es eine Verzweigung mit zwei Spalten, in jeder ein
return:
weight(index): if index mod 2 == 0: return 1 else: return 3
def weight(index) if index.even? 1 else 3 end end
Ob eine Zahl gerade ist, sagt der Rest bei der Division durch 2: index % 2
ist 0 oder 1.
Als Struktogramm ist es eine Verzweigung mit zwei Spalten, in jeder ein
return:
weight(index): if index mod 2 == 0: return 1 else: return 3
def weight(index): if index % 2 == 0: return 1 else: return 3
Schreib in check-digits/check_digits.rb die Funktion weight(index):
Sie gibt für einen geraden Index 1 zurück und für einen ungeraden 3. Die
Prüfung ruft weight(0), weight(1), weight(4) und weight(11) auf.
Schreib in check-digits/check_digits.py die Funktion weight(index):
Sie gibt für einen geraden Index 1 zurück und für einen ungeraden 3. Die
Prüfung ruft weight(0), weight(1), weight(4) und weight(11) auf.
check_digit von oben in Code, Kasten für Kasten, unter
weight in dieselbe Datei.
Wie die Bausteine in Ruby heißen, steht im Handbuch unter
Vom Pseudocode zum Code:
← ist =, mod ist %, und for i from 0 to 11 ist (0..11).each do |i|.
def check_digit(digits) total = 0 (0..11).each do |i| total = total + weight(i) * digits[i] end (10 - total % 10) % 10 end
irb
check_digit([4, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) auf; heraus kommt
die 1 aus der Tabelle oben. Nimm dann das letzte % 10 weg, starte
neu und ruf check_digit([4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]) auf. Achte darauf,
ob das Ergebnis noch eine Ziffer ist, und setz das % 10 danach wieder ein.
Wie die Bausteine in Python heißen, steht im Handbuch unter
Vom Pseudocode zum Code:
← ist =, mod ist %, und for i from 0 to 11 ist
for i in range(0, 12), denn range hört eins vor dem Ende auf.
def check_digit(digits): total = 0 for i in range(0, 12): total = total + weight(i) * digits[i] return (10 - total % 10) % 10
check_digit([4, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) auf; heraus kommt
die 1 aus der Tabelle oben. Nimm dann das letzte % 10 weg, starte
neu und ruf check_digit([4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]) auf. Achte darauf,
ob das Ergebnis noch eine Ziffer ist, und setz das % 10 danach wieder ein.
Schreib check_digit(digits) nach dem Struktogramm. digits ist eine
Liste von zwölf Zahlen. Die Prüfung ruft die Funktion mit den Ziffern
von 4 260111 02043 auf, mit zwölf Nullen und mit
[4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2].
Schreib check_digit(digits) nach dem Struktogramm. digits ist eine
Liste von zwölf Zahlen. Die Prüfung ruft die Funktion mit den Ziffern
von 4 260111 02043 auf, mit zwölf Nullen und mit
[4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2].
Bisher stand der Plan schon da, und du hast ihn übersetzt. Ab jetzt planst du selbst, und zwar gleich dort, wo der Code hinkommt: Du legst die Funktion an und schreibst als Kommentare hinein, was sie Schritt für Schritt tun soll, noch ohne eine Zeile Code. Dabei klärst du drei Fragen: Was bekommt die Funktion, und was gibt sie zurück? Welche Fälle gibt es, auch solche, die nicht vorkommen sollten? Und in welcher Reihenfolge geschieht was?
Dann ersetzt du einen Kommentar nach dem anderen durch Code und probierst nach jedem Schritt aus. Die Kommentare dürfen stehen bleiben: Wer den Code später liest, sieht so, wofür jeder Teil da ist. Genauso planen viele, die beruflich programmieren; der Plan ist Pseudocode, nur eben in der Datei.
Die Kasse bekommt, was die Kassiererin getippt hat, als Text, und will wissen: Ist das ein gültiger Code? Er ist es, wenn er aus genau 13 Ziffern besteht und die letzte die Prüfziffer der ersten zwölf ist.
valid_ean?(code)
an und schreib zuerst deinen Plan als Kommentare hinein, dann den Code dazu.
Sie gibt true oder false zurück und benutzt
check_digit.
Was macht einen Code sicher ungültig, bevor man rechnet? Wenn er zu kurz oder
zu lang ist, und wenn ein Zeichen keine Ziffer ist. Prüf das zuerst und gib
dann gleich false zurück.
Ein Plan, dem noch der Code fehlt:
def valid_ean?(code) # nicht genau 13 Zeichen: false # ein Zeichen ist keine Ziffer: false # die 13 Zeichen als Zahlen # gültig, wenn die Prüfziffer der ersten zwölf gleich der dreizehnten ist end
Für die Einzelheiten in Ruby: code.length ist die Zahl der Zeichen,
code.chars die Liste der Zeichen, ('0'..'9').include?(c) sagt, ob c eine
Ziffer ist, c.to_i macht aus '7' die Zahl 7, und digits[0..11] sind die
ersten zwölf Elemente einer Liste.
def valid_ean?(code) # nicht genau 13 Zeichen: false return false unless code.length == 13 # ein Zeichen ist keine Ziffer: false return false unless code.chars.all? { |c| ('0'..'9').include?(c) } # die 13 Zeichen als Zahlen digits = code.chars.map(&:to_i) # gültig, wenn die Prüfziffer der ersten zwölf gleich der dreizehnten ist check_digit(digits[0..11]) == digits[12] end
is_valid_ean(code)
an und schreib zuerst deinen Plan als Kommentare hinein, dann den Code dazu.
Sie gibt True oder False zurück und benutzt
check_digit.
Was macht einen Code sicher ungültig, bevor man rechnet? Wenn er zu kurz oder
zu lang ist, und wenn ein Zeichen keine Ziffer ist. Prüf das zuerst und gib
dann gleich False zurück.
Ein Plan, dem noch der Code fehlt. Damit Python die Funktion schon jetzt
annimmt, steht am Ende pass, das nichts tut:
def is_valid_ean(code): # nicht genau 13 Zeichen: False # ein Zeichen ist keine Ziffer: False # die 13 Zeichen als Zahlen # gültig, wenn die Prüfziffer der ersten zwölf gleich der dreizehnten ist pass
Für die Einzelheiten in Python: len(code) ist die Zahl der Zeichen,
c in '0123456789' sagt, ob c eine Ziffer ist, int(c) macht aus '7' die
Zahl 7, und digits[0:12] sind die ersten zwölf Elemente einer Liste.
def is_valid_ean(code): # nicht genau 13 Zeichen: False if len(code) != 13: return False # ein Zeichen ist keine Ziffer: False if not all(c in '0123456789' for c in code): return False # die 13 Zeichen als Zahlen digits = [int(c) for c in code] # gültig, wenn die Prüfziffer der ersten zwölf gleich der dreizehnten ist return check_digit(digits[0:12]) == digits[12]
Schreib valid_ean?(code): Sie bekommt einen Code als String und gibt
true zurück, wenn er aus genau 13 Ziffern besteht und die letzte
die richtige Prüfziffer ist, sonst false. Die Prüfung ruft sie mit
gültigen und ungültigen Codes auf, auch mit zu kurzen, zu langen und
solchen mit Buchstaben.
Schreib is_valid_ean(code): Sie bekommt einen Code als String und gibt
True zurück, wenn er aus genau 13 Ziffern besteht und die letzte
die richtige Prüfziffer ist, sonst False. Die Prüfung ruft sie mit
gültigen und ungültigen Codes auf, auch mit zu kurzen, zu langen und
solchen mit Buchstaben.
Bücher tragen eine ISBN (International Standard Book Number). Bis 2007
hatte sie zehn Zeichen, etwa 3-499-12304-5; die Bindestriche trennen nur
Gruppen und zählen nicht mit. Ihre Prüfung geht anders als beim Strichcode:
Die letzte Ziffer ist also so gewählt, dass die Summe aufgeht. Manchmal müsste
sie dafür 10 sein, und das ist keine Ziffer: Dann steht dort ein X, wie die
römische Zehn. Ein X gibt es nur an dieser Stelle.
Für 3-499-12304-5 ist die Summe
3 · 10 + 4 · 9 + 9 · 8 + 9 · 7 + 1 · 6 + 2 · 5 + 3 · 4 + 0 · 3 + 4 · 2 + 5 · 1
= 242 = 22 · 11; die ISBN ist gültig.
Diesmal steht kein Plan auf der Seite. Leg valid_isbn?(isbn) an und schreib
deinen Plan als Kommentare hinein, bevor du Code schreibst: Was geschieht mit
den Bindestrichen, was mit einem X, was mit einem Zeichen, das weder Ziffer
noch X ist?
Diesmal steht kein Plan auf der Seite. Leg is_valid_isbn(isbn) an und schreib
deinen Plan als Kommentare hinein, bevor du Code schreibst: Was geschieht mit
den Bindestrichen, was mit einem X, was mit einem Zeichen, das weder Ziffer
noch X ist?
Kopier die Kommentare deines Plans für valid_isbn? hierher, bevor du
den Code dazu schreibst. Deine Lehrkraft sieht sie.
Kopier die Kommentare deines Plans für is_valid_isbn hierher, bevor
du den Code dazu schreibst. Deine Lehrkraft sieht sie.
Schreib valid_isbn?(isbn) nach deinem Plan. Die Prüfung ruft sie mit
ISBNs mit und ohne Bindestriche auf, mit einem X am Ende, mit einem X an
der falschen Stelle und mit falschen Ziffern.
Schreib is_valid_isbn(isbn) nach deinem Plan. Die Prüfung ruft sie mit
ISBNs mit und ohne Bindestriche auf, mit einem X am Ende, mit einem X an
der falschen Stelle und mit falschen Ziffern.
Ein häufiger Fehler beim Abtippen ist nicht die falsche Ziffer, sondern der Zahlendreher: zwei benachbarte Ziffern in der falschen Reihenfolge.
Die Kassiererin vertauscht zwei benachbarte Ziffern, die verschieden
sind, etwa 42 statt 24. Merkt die Kasse das?
Hier geht es weiter, sobald du deine Antwort oben abgegeben hast.
Ausrechnen kannst du es mit einem kleinen Programm, das alle Möglichkeiten
ausprobiert. Für zwei verschiedene Ziffern a und b gibt es 10 · 9 = 90
Paare. Es genügt, jedes Paar an den Anfang eines Codes zu stellen, den Rest mit
Nullen zu füllen und die Prüfziffer anzuhängen; dann ist der Code gültig.
Vertauscht man nun die ersten beiden Ziffern: Ist der Code danach immer noch
gültig, hat die Kasse den Zahlendreher nicht bemerkt.
swaps.rb ein Programm, das die 90 Paare durchgeht und zählt, wie
viele Zahlendreher valid_ean? nicht bemerkt. Die erste Zeile
require_relative 'check_digits' holt deine Funktionen dazu.
Zwei Schleifen ineinander gehen alle Paare durch: außen a von 0 bis 9, innen
b von 0 bis 9; ist a == b, geht es mit dem nächsten weiter (next).
Für ein Paar: digits = [a, b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dann ist
code = (digits + [check_digit(digits)]).join ein gültiger Code.
code[1] + code[0] + code[2..] ist derselbe Code mit vertauschten ersten
Ziffern.
require_relative 'check_digits' missed = 0 (0..9).each do |a| (0..9).each do |b| next if a == b digits = [a, b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] code = (digits + [check_digit(digits)]).join swapped = code[1] + code[0] + code[2..] missed = missed + 1 if valid_ean?(swapped) end end puts "Unbemerkt: #{missed} von 90"
ruby swaps.rb
swaps.py ein Programm, das die 90 Paare durchgeht und zählt, wie
viele Zahlendreher is_valid_ean nicht bemerkt. Die erste Zeile
from check_digits import check_digit, is_valid_ean holt deine
Funktionen dazu.
Zwei Schleifen ineinander gehen alle Paare durch: außen a von 0 bis 9, innen
b von 0 bis 9; ist a == b, geht es mit dem nächsten weiter (continue).
Für ein Paar: digits = [a, b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dann ist
code = ''.join(str(d) for d in digits + [check_digit(digits)]) ein gültiger
Code. code[1] + code[0] + code[2:] ist derselbe Code mit vertauschten ersten
Ziffern.
from check_digits import check_digit, is_valid_ean missed = 0 for a in range(0, 10): for b in range(0, 10): if a == b: continue digits = [a, b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] code = ''.join(str(d) for d in digits + [check_digit(digits)]) swapped = code[1] + code[0] + code[2:] if is_valid_ean(swapped): missed = missed + 1 print(f"Unbemerkt: {missed} von 90")
python3 swaps.py
Wie viele der 90 Zahlendreher aus zwei verschiedenen Ziffern merkt
valid_ean? nicht?
Wie viele der 90 Zahlendreher aus zwei verschiedenen Ziffern merkt
is_valid_ean nicht?
Hier geht es weiter, sobald du deine Antwort oben abgegeben hast.
Unbemerkt bleiben genau die Paare, deren Ziffern sich um 5 unterscheiden, etwa
05 und 50. Beim Vertauschen tauschen die beiden Ziffern ihre Gewichte 1 und
3; die Summe ändert sich dadurch um das Doppelte ihres Unterschieds. Ist der
Unterschied 5, ändert sie sich um 10, und die Prüfziffer bleibt dieselbe.
Wie viele Zahlendreher aus zwei verschiedenen Ziffern merkt die ISBN nicht?
Ein Extra für Schnelle. Wer es auslässt, springt zu Zum Nachschlagen.