Personalausweis

 #! /usr/bin/tclsh

 if false {

The German identity card is called Personalausweis. It has a unique number. In some cases, for age checking, this number is to be input in internet forms. I found a homepage [1 ] describing how the number is set up. As an exercise, I made this number generator. wdb

 }

 # Personalausweis-Nr. generieren
 # Quelle:
 # Prüfziffern: Deutscher Personalausweis
 # http://www.pruefziffernberechnung.de/P/Personalausweis-DE.shtml

 set behoerdenkennzahlen {
  0302 0303 0308 0309 0314 0316 0318 0339 0349 0350 0359 0360
  0360 0360 0361 0368 0370 0371 0375 0384 0385 0387 0389 0395
  0413 0417 0428 0451 0484 0486 0500 1000 1001 1004 1006 1007
  1011 1013 1014 1015 1016 1021 1022 1029 1039 1049 1058 1066
  1090 1103 1105 1106 1119 1123 1130 1131 1133 1134 1136 1138
  1139 1141 1142 1170 1176 1183 1189 1197 1200 1204 1206 1211
  1213 1239 1241 1245 1250 1252 1253 1257 1296 1296 1297 1297
  1298 1300 1300 1304 1304 1307 1307 1308 1308 1308 1308 1311
  1312 1317 1323 1325 1333 1336 1339 1340 1340 1343 1346 1348
  1350 1352 1353 1354 1360 1373 1373 1375 1375 1375 1376 1377
  1377 1377 1382 1384 1388 1394 1396 1397 1398 1412 1413 1421
  1421 1428 1429 1437 1439 1442 1450 1456 1463 1464 1465 1468
  1474 1482 1482 1483 1485 1485 1487 1492 1493 1495 1497 1500
  1504 1505 1508 1509 1510 1515 1517 1518 1519 1520 1521 1522
  1523 1524 1525 1526 1527 1528 1531 1532 1532 1532 1534 1537
  1543 1545 1547 1551 1553 1554 1556 1582 1587 1588 1591 1592
  1598 1600 1601 1602 1605 1610 1612 1614 1616 1618 1620 1628
  1629 1630 1632 1633 1634 1635 1636 1637 1638 1641 1648 1649
  1651 1654 1655 1656 1657 1657 1659 1660 1661 1668 1668 1670
  1670 1671 1676 1681 1683 1684 1686 1687 1689 1691 1694 1702
  1705 1714 1716 1717 1718 1720 1720 1722 1726 1727 1729 1730
  1736 1738 1740 1741 1744 1745 1746 1749 1750 1751 1754 1757
  1757 1759 1760 1761 1762 1763 1765 1766 1768 1769 1770 1773
  1774 1779 1780 1781 1782 1784 1785 1787 1788 1789 1791 1805
  1808 1813 1814 1815 1816 1817 1818 1819 1820 1821 1831 1833
  1837 1838 1842 1843 1844 1845 1845 1846 1847 1848 1848 1849
  1855 1856 1858 1859 1861 1865 1872 1873 1874 1877 1878 1879
  1880 1881 1882 1884 1885 1886 1887 1889 1890 1891 1895 1896
  1896 2002 2004 2004 2005 2006 2007 2007 2008 2009 2010 2012
  2013 2019 2031 2039 2040 2046 2053 2060 2061 2075 2080 2082
  2089 2091 2105 2106 2108 2111 2113 2114 2115 2118 2119 2120
  2122 2124 2126 2132 2135 2136 2137 2140 2143 2146 2154 2157
  2159 2160 2166 2166 2167 2168 2171 2172 2173 2174 2175 2180
  2182 2182 2184 2192 2193 2196 2203 2205 2208 2209 2216 2218
  2221 2223 2224 2225 2227 2231 2232 2236 2242 2243 2245 2247
  2251 2252 2255 2261 2262 2263 2264 2270 2312 2313 2314 2315
  2321 2324 2326 2330 2332 2333 2338 2344 2360 2374 2388 2389
  2394 2399 2401 2403 2406 2408 2414 2415 2417 2422 2423 2425
  2427 2429 2431 2432 2433 2436 2437 2437 2440 2442 2444 2445
  2447 2449 2453 2454 2455 2456 2458 2460 2463 2465 2466 2466
  2469 2470 2471 2472 2472 2473 2475 2477 2478 2488 2493 2495
  2497 2499 2499 2500 2500 2504 2506 2506 2507 2508 2509 2510
  2512 2513 2514 2518 2519 2520 2523 2527 2528 2531 2533 2533
  2534 2536 2538 2540 2545 2547 2548 2551 2552 2552 2554 2554
  2555 2556 2579 2584 2591 2598 2615 2618 2635 2635 2635 2636
  2640 2645 2651 2661 2662 2671 2672 2676 2678 2689 2692 2694
  2695 2696 2703 2708 2712 2719 2720 2726 2738 2739 2745 2755
  2758 2781 2786 2798 2809 2828 2833 2835 2854 2854 2854 2855
  2880 3223 3241 326 3316 3333 3347 3501 3505 3507 3508 3518
  3523 3533 3541 3543 3549 3550 3551 3551 3555 3556 3560 3572
  3600 3601 3602 4000 4001 4002 4003 4007 4008 4009 4011 4012
  4014 4014 4015 4017 4020 4021 4026 4026 4026 4027 4028 4033
  4037 4048 4055 4057 4058 4063 4066 4069 4071 4074 4076 4077
  4079 4080 4082 4084 4085 4086 4086 4087 4089 4092 4093 4095
  4097 4098 4101 4101 4102 4103 4106 4115 4119 4121 4124 4133
  4143 4144 4145 4150 4151 4152 4158 4163 4164 4169 4171 4175
  4176 4178 4179 4182 4185 4197 4199 4200 4203 4205 4212 4217
  4227 4228 4229 4232 4234 4235 4243 4247 4251 4253 4256 4262
  4263 4263 4265 4266 4271 4273 4274 4275 4285 4292 4298 4302
  4303 4309 4309 4310 4315 4317 4320 4320 4322 4342 4349 4350
  4351 4361 4373 4393 4404 4406 4411 4413 4421 4427 4428 4446
  4448 4450 4459 4463 4464 4487 4701 4717 4739 4742 4763 4764
  4765 4765 4766 4767 4774 4775 4802 4804 4812 4817 4823 4824
  4828 4847 4850 4881 4885 4935 4964 4978 4983 4983 5002 5003
  5003 5004 5004 5005 5006 5007 5008 5008 5009 5010 5011 5011
  5021 5023 5026 5030 5031 5035 5037 5041 5042 5045 5046 5047
  5049 5050 5051 5060 5060 5061 5062 5065 5066 5071 5072 5076
  5078 5083 5087 5090 5094 5095 5096 5103 5104 5105 5106 5109
  5115 5117 5119 5123 5125 5129 5131 5132 5135 5137 5140 5141
  5143 5144 5147 5147 5148 5151 5152 5158 5159 5162 5165 5169
  5170 5171 5172 5174 5178 5184 5185 5187 5197 5198 5199 5200
  5201 5204 5205 5206 5208 5208 5209 5210 5215 5216 5218 5218
  5219 5224 5228 5229 5230 5230 5234 5234 5237 5238 5240 5244
  5245 5247 5249 5255 5258 5263 5268 5270 5278 5283 5284 5286
  5289 5291 5293 5296 5297 5299 5307 5312 5316 5318 5325 5326
  5333 5337 5339 5340 5343 5345 5347 5348 5351 5353 5355 5356
  5358 5360 5361 5363 5367 5369 5371 5372 5373 5374 5377 5380
  5381 5382 5383 5384 5389 5390 5393 5394 5398 5400 5404 5417
  5420 5429 5430 5431 5432 5434 5436 5437 5439 5440 5442 5444
  5445 5447 5448 5450 5451 5452 5452 5453 5459 5462 5465 5472
  5473 5474 5475 5475 5475 5475 5479 5479 5485 5487 5489 5491
  5495 5500 5500 5502 5505 5507 5509 5509 5511 5519 5520 5522
  5527 5530 5532 5533 5534 5538 5538 5542 5552 5555 5557 5560
  5563 5566 5568 5570 5573 5574 5578 5578 5581 5582 5582 5582
  5585 5587 5597 5597 5597 5598 5598 5598 5599 5599 5599 5602
  5604 5605 5606 5607 5608 5608 5610 5610 5611 5617 5618 5625
  5627 5632 5636 5637 5638 5640 5643 5649 5651 5654 5655 5656
  5658 5663 5664 5667 5670 5679 5683 5684 5686 5687 5690 5691
  5701 5702 5703 5704 5706 5711 5718 5722 5726 5727 5733 5737
  5740 5743 5745 5751 5753 5755 5760 5761 5762 5764 5766 5770
  5772 5785 5790 6002 6004 6005 6006 6007 6008 6009 6009 6010
  6010 6019 6027 6029 6031 6037 6038 6040 6042 6043 6058 6059
  6076 6078 6078 6078 6084 6088 6090 6092 6093 6094 6097 6102
  6107 6112 6117 6126 6133 6143 6145 6149 6154 6156 6157 6163
  6173 6176 6187 6190 6201 6203 6207 6211 6212 6213 6215 6216
  6217 6219 6225 6228 6229 6230 6288 6290 6291 6293 6296 6303
  6318 6319 6335 6336 6343 6364 6364 6377 6382 6386 6390 6394
  6394 6395 6395 6396 6396 6407 6409 6412 6421 6423 6424 6431
  6432 6436 6436 6438 6448 6462 6466 6467 6471 6475 6475 6476
  6476 6483 6493 6510 6511 6513 6520 6528 6530 6542 6548 6549
  6553 6556 6566 6569 6570 6580 6586 6590 6591 6593 6598 6599
  6605 6611 6615 6641 6642 6642 6643 6644 6675 6698 6719 6737
  6741 6748 6750 6767 6775 6776 6786 6788 6801 6802 6804 6809
  6810 6812 6815 6815 6815 6815 6815 6815 6815 6815 6815 6817
  6828 6837 6839 6841 6849 6852 6857 6862 6869 6877 6884 6889
  6903 6914 6921 6924 6934 6947 6968 6970 6986 6987 7003 7009
  7017 7019 7020 7034 7035 7046 7047 7072 7075 7092 7103 7124
  7124 7126 7131 7134 7139 7140 7147 7154 7159 7165 7169 7175
  7176 7178 7204 7491 7605 7608 7610 7612 7619 7620 7621 7622
  7623 7624 7625 7625 7625 7626 7626 7632 7634 7635 7636 7636
  7637 7643 7646 7648 7649 7650 7656 7657 7658 7659 7660 7661
  7662 7663 7664 7665 7665 7666 7667 7668 7669 7670 7672 7674
  7675 7678 7689 7690 7691 7692 7693 7695 7698 7698 7699 7700
  7701 7704 7705 7706 7713 7714 7717 7720 7721 7722 7724 7725
  7727 7728 7729 7731 7736 7737 7738 7739 7740 7741 7745 7746
  7747 7748 7749 7750 7751 7753 7757 7758 7759 7760 7761 7762
  7766 7766 7771 7772 7773 7776 7782 7783 7784 7785 7792 7793
  7804 7805 7806 7807 7808 7813 7828 7829 7831 7832 7834 7835
  7839 7841 7844 7846 7847 7851 7852 7855 7856 7857 7865 7866
  7867 7868 7871 7876 7879 7881 7882 7884 7888 7894 7896 7897
  7898 7901 7909 7911 7916 7917 7926 7927 7928 7928 7930 7931
  7935 7940 7943 7944 7946 7947 7947 7948 7952 7954 7959 7963
  7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7975 7976
  7979 7980 7983 7984 7985 7989 7990 7992 7994 8001 8001 8007
  8012 8013 8015 8016 8017 8018 8018 8019 8020 8021 8023 8023
  8024 8025 8026 8027 8038 8044 8048 8057 8072 8077 8084 8088
  8092 8094 8095 8100 8101 8103 8113 8114 8118 8119 8120 8122
  8124 8128 8129 8134 8138 8145 8146 8150 8153 8157 8163 8165
  8166 8168 8170 8172 8174 8175 8176 8179 8179 8182 8185 8186
  8187 8190 8191 8193 8197 8206 8240 8248 8249 8250 8254 8257
  8258 8260 8261 8262 8263 8264 8267 8268 8268 8272 8274 8275
  8280 8282 8283 8283 8284 8287 8291 8306 8318 8325 8326 8330
  8340 8347 8350 8351 8352 8354 8355 8355 8356 8359 8361 8386
  8397 8399 8400 8405 8406 8409 8411 8413 8416 8421 8428 8435
  8444 8459 8468 8469 8469 8471 8473 8480 8482 8483 8487 8513
  8520 8529 8535 8539 8541 8542 8546 8550 8581 8584 8586 8593
  8596 8597 8600 8602 8611 8612 8615 8623 8649 8649 8650 8651
  8652 8653 8654 8655 8657 8658 8660 8660 8661 8662 8663 8664
  8665 8685 8688 8689 8693 8694 8699 8708 8709 8715 8717 8723
  8727 8732 8736 8738 8740 8740 8749 8749 8752 8753 8753 8755
  8758 8774 8804 8806 8812 8825 8834 8840 8842 8844 8848 8848
  8850 8854 8875 8887 8893 8896 8902 8905 8910 8912 8913 8913
  8916 8917 8917 8919 8920 8921 8922 8923 8924 8924 8925 8926
  8926 8934 8941 8941 8944 8949 8952 8955 8967 8971 8973 8985
  8986 8987 8995 8996 8999 9000 9029 9031 9037 9040 9041 9048
  9049 9056 9057 9058 9063 9064 9064 9070 9072 9081 9083 9093
  9094 9104 9140 9148 9156 9162 9166 9172 9173 9181 9206 9218
  9231 9236 9242 9246 9249 9252 9262 9272 9275 9300 9304 9310
  9314 9318 9338 9345 9348 9356 9358 9363 9370 9396 9404 9412
  9413 9415 9430 9444 9447 9482 9503 9508 9509 9510 9511 9513
  9515 9544 9703 9704 9717 9718 9719 9730 9732 9732 9738 9738
  9748 9748 9749 9749 9753 9760 9761 9762 9775 9783 9784 9785
  9788 9793 9796 9811 9816 9818 9820 9823 9834 9845 9859 9864
  9871 9872 9879 9883 9923 9941 9949 9961 9976 9986
 }

 proc behoerdenkennzahl {} {
  variable behoerdenkennzahlen
  lindex $behoerdenkennzahlen\
    [expr {int(rand() * [llength $behoerdenkennzahlen])}]
 }

 proc laufendeNr {} {
  format %05d [expr {int(rand() * 100000)}]
 }

 proc pruefZiffer n {
  set sum 0
  foreach {a b c} [split $n ""] {
    incr sum [expr {$a * 7}]
    if {$b ne ""} then {
      incr sum [expr {$b * 3}]
      if {$c ne ""} then {
        incr sum $c
      }
    }
  }
  string index $sum end
 }

 proc personalausweisNr args {
  array set opt [concat {
    -jahr 1950
    -monat 1
    -tag 1
    -ablauf ""
  } $args]
  set seriennummer [behoerdenkennzahl][laufendeNr]
  append seriennummer [pruefZiffer $seriennummer]
  append result $seriennummer D<<
  set geburtstag [string range $opt(-jahr) end-1 end]
  append geburtstag [format %02d $opt(-monat)] [format %02d $opt(-tag)]
  append geburtstag [pruefZiffer $geburtstag]
  append result $geburtstag <
  if {$opt(-ablauf) eq ""} then {
    set ablaufjahr [expr {[clock format [clock seconds] -format %Y] + 8}]
  } else {
    set ablaufjahr $opt(-ablauf)
  }
  append ablaufjahr 01 01
  append ablaufjahr [pruefZiffer $ablaufjahr]
  append result $ablaufjahr < < < < < < <
  append result [pruefZiffer $seriennummer$geburtstag$ablaufjahr]
 }

 if {[lsearch $argv -h*] >= 0} then {
  puts "$argv0 ?-jahr jjjj? ?-monat mm? ?-tag tt?"
 } else {
  puts "[eval personalausweisNr $argv]"
 }