[{"data":1,"prerenderedAt":2555},["ShallowReactive",2],{"doc:\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fvalidate-check-digits-in-excel-data-with-python":3,"surround:\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fvalidate-check-digits-in-excel-data-with-python":2521,"ancestors:\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fvalidate-check-digits-in-excel-data-with-python":2530,"children:\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fvalidate-check-digits-in-excel-data-with-python":2535,"related:\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fvalidate-check-digits-in-excel-data-with-python":2536},{"id":4,"title":5,"body":6,"dateModified":2488,"datePublished":2488,"description":2489,"extension":2490,"faq":2491,"keyword":2500,"kind":2501,"meta":2502,"navigation":103,"path":2511,"seo":2512,"slug":2515,"stem":2516,"topics":2517,"type":2519,"__hash__":2520},"docs\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fvalidate-check-digits-in-excel-data-with-python\u002Findex.md","Validate Check Digits in Excel Data with Python",{"type":7,"value":8,"toc":2475},"minimark",[9,24,29,61,71,75,181,200,204,207,523,537,891,895,898,1250,1271,1275,1278,1517,1524,1654,1658,1664,1827,1838,1842,1845,2187,2194,2361,2365,2400,2404,2410,2414,2420,2426,2432,2438,2442,2471],[10,11,12,13,17,18,23],"p",{},"A product list with a mistyped barcode, a supplier sheet with a wrong IBAN, a customer file with a reference number missing a digit: each of these is cheap to catch at import and expensive to discover after a shipment goes to the wrong place or a payment bounces. Many identifiers include a ",[14,15,16],"em",{},"check digit"," — a last digit computed from the others — precisely so that software can catch typing errors without looking anything up. Swapped neighbouring digits and single wrong digits, the two most common typos, fail the check. This page validates three widespread schemes in a spreadsheet column: GTIN\u002FEAN barcodes, IBANs and the Luhn algorithm, and marks the failures in the workbook. It belongs to ",[19,20,22],"a",{"href":21},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002F","Validating Excel Data with Python",".",[25,26,28],"h2",{"id":27},"prerequisites","Prerequisites",[30,31,36],"pre",{"className":32,"code":33,"language":34,"meta":35,"style":35},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas openpyxl python-stdnum\n","bash","",[37,38,39],"code",{"__ignoreMap":35},[40,41,44,48,52,55,58],"span",{"class":42,"line":43},"line",1,[40,45,47],{"class":46},"sMTad","pip",[40,49,51],{"class":50},"srMev"," install",[40,53,54],{"class":50}," pandas",[40,56,57],{"class":50}," openpyxl",[40,59,60],{"class":50}," python-stdnum\n",[10,62,63,66,67,70],{},[37,64,65],{},"suppliers.xlsx"," lists six suppliers with an IBAN, a product barcode and a card-style reference number. Some values are valid, some have a single wrong digit, some contain spaces. The IBANs and card numbers are the standard published test numbers, not real accounts. ",[37,68,69],{},"python-stdnum"," is used at the end to cross-check the hand-written validators.",[25,72,74],{"id":73},"step-1-read-identifiers-as-text","Step 1 — Read identifiers as text",[30,76,80],{"className":77,"code":78,"language":79,"meta":35,"style":35},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\nsup = pd.read_excel(\"suppliers.xlsx\", dtype=str)\nprint(sup.dtypes.to_dict())\nprint(sup[[\"Barcode\", \"CardRef\"]].head(3).to_string(index=False))\n","python",[37,81,82,98,105,136,145],{"__ignoreMap":35},[40,83,84,88,92,95],{"class":42,"line":43},[40,85,87],{"class":86},"s-kum","import",[40,89,91],{"class":90},"skGVy"," pandas ",[40,93,94],{"class":86},"as",[40,96,97],{"class":90}," pd\n",[40,99,101],{"class":42,"line":100},2,[40,102,104],{"emptyLinePlaceholder":103},true,"\n",[40,106,108,111,114,117,120,123,127,129,133],{"class":42,"line":107},3,[40,109,110],{"class":90},"sup ",[40,112,113],{"class":86},"=",[40,115,116],{"class":90}," pd.read_excel(",[40,118,119],{"class":50},"\"suppliers.xlsx\"",[40,121,122],{"class":90},", ",[40,124,126],{"class":125},"sa561","dtype",[40,128,113],{"class":86},[40,130,132],{"class":131},"sP0c6","str",[40,134,135],{"class":90},")\n",[40,137,139,142],{"class":42,"line":138},4,[40,140,141],{"class":131},"print",[40,143,144],{"class":90},"(sup.dtypes.to_dict())\n",[40,146,148,150,153,156,158,161,164,167,170,173,175,178],{"class":42,"line":147},5,[40,149,141],{"class":131},[40,151,152],{"class":90},"(sup[[",[40,154,155],{"class":50},"\"Barcode\"",[40,157,122],{"class":90},[40,159,160],{"class":50},"\"CardRef\"",[40,162,163],{"class":90},"]].head(",[40,165,166],{"class":131},"3",[40,168,169],{"class":90},").to_string(",[40,171,172],{"class":125},"index",[40,174,113],{"class":86},[40,176,177],{"class":131},"False",[40,179,180],{"class":90},"))\n",[10,182,183,184,187,188,191,192,195,196,23],{},"Read every identifier column with ",[37,185,186],{},"dtype=str",". Read as numbers, a barcode starting with ",[37,189,190],{},"0"," loses its leading zero, and a 16-digit card reference loses its last digit to floating-point rounding — Excel and pandas both keep only about 15 significant digits. Either change makes a valid number fail its check. If the file was ",[14,193,194],{},"saved"," by Excel with such columns stored as numbers, the digits may already be gone; the cure is in ",[19,197,199],{"href":198},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-long-id-numbers-losing-digits-in-excel\u002F","Fix Long ID Numbers Losing Digits in Excel",[25,201,203],{"id":202},"step-2-gtin-ean-13-barcodes","Step 2 — GTIN \u002F EAN-13 barcodes",[10,205,206],{},"The last digit of a GTIN (EAN-8, UPC-A, EAN-13, GTIN-14) makes a weighted sum a multiple of ten: working from the right, digits are weighted 3, 1, 3, 1… with the check digit itself weight 1.",[30,208,210],{"className":77,"code":209,"language":79,"meta":35,"style":35},"def gtin_valid(code):\n    digits = \"\".join(ch for ch in str(code) if ch.isdigit())\n    if len(digits) not in (8, 12, 13, 14) or digits != str(code).replace(\" \", \"\"):\n        return False\n    body, check = digits[:-1], int(digits[-1])\n    total = sum(int(d) * (3 if i % 2 == 0 else 1) for i, d in enumerate(reversed(body)))\n    return (10 - total % 10) % 10 == check\n\nsup[\"Barcode OK\"] = sup[\"Barcode\"].map(gtin_valid)\nprint(sup[[\"Supplier\", \"Barcode\", \"Barcode OK\"]].to_string(index=False))\n",[37,211,212,224,258,324,332,364,434,467,472,494],{"__ignoreMap":35},[40,213,214,217,221],{"class":42,"line":43},[40,215,216],{"class":86},"def",[40,218,220],{"class":219},"s_Opv"," gtin_valid",[40,222,223],{"class":90},"(code):\n",[40,225,226,229,231,234,237,240,243,246,249,252,255],{"class":42,"line":100},[40,227,228],{"class":90},"    digits ",[40,230,113],{"class":86},[40,232,233],{"class":50}," \"\"",[40,235,236],{"class":90},".join(ch ",[40,238,239],{"class":86},"for",[40,241,242],{"class":90}," ch ",[40,244,245],{"class":86},"in",[40,247,248],{"class":131}," str",[40,250,251],{"class":90},"(code) ",[40,253,254],{"class":86},"if",[40,256,257],{"class":90}," ch.isdigit())\n",[40,259,260,263,266,269,272,275,278,281,283,286,288,291,293,296,299,302,305,308,310,313,316,318,321],{"class":42,"line":107},[40,261,262],{"class":86},"    if",[40,264,265],{"class":131}," len",[40,267,268],{"class":90},"(digits) ",[40,270,271],{"class":86},"not",[40,273,274],{"class":86}," in",[40,276,277],{"class":90}," (",[40,279,280],{"class":131},"8",[40,282,122],{"class":90},[40,284,285],{"class":131},"12",[40,287,122],{"class":90},[40,289,290],{"class":131},"13",[40,292,122],{"class":90},[40,294,295],{"class":131},"14",[40,297,298],{"class":90},") ",[40,300,301],{"class":86},"or",[40,303,304],{"class":90}," digits ",[40,306,307],{"class":86},"!=",[40,309,248],{"class":131},[40,311,312],{"class":90},"(code).replace(",[40,314,315],{"class":50},"\" \"",[40,317,122],{"class":90},[40,319,320],{"class":50},"\"\"",[40,322,323],{"class":90},"):\n",[40,325,326,329],{"class":42,"line":138},[40,327,328],{"class":86},"        return",[40,330,331],{"class":131}," False\n",[40,333,334,337,339,342,345,348,351,354,357,359,361],{"class":42,"line":147},[40,335,336],{"class":90},"    body, check ",[40,338,113],{"class":86},[40,340,341],{"class":90}," digits[:",[40,343,344],{"class":86},"-",[40,346,347],{"class":131},"1",[40,349,350],{"class":90},"], ",[40,352,353],{"class":131},"int",[40,355,356],{"class":90},"(digits[",[40,358,344],{"class":86},[40,360,347],{"class":131},[40,362,363],{"class":90},"])\n",[40,365,367,370,372,375,378,380,383,386,388,390,393,396,399,402,405,408,411,414,416,418,421,423,426,428,431],{"class":42,"line":366},6,[40,368,369],{"class":90},"    total ",[40,371,113],{"class":86},[40,373,374],{"class":131}," sum",[40,376,377],{"class":90},"(",[40,379,353],{"class":131},[40,381,382],{"class":90},"(d) ",[40,384,385],{"class":86},"*",[40,387,277],{"class":90},[40,389,166],{"class":131},[40,391,392],{"class":86}," if",[40,394,395],{"class":90}," i ",[40,397,398],{"class":86},"%",[40,400,401],{"class":131}," 2",[40,403,404],{"class":86}," ==",[40,406,407],{"class":131}," 0",[40,409,410],{"class":86}," else",[40,412,413],{"class":131}," 1",[40,415,298],{"class":90},[40,417,239],{"class":86},[40,419,420],{"class":90}," i, d ",[40,422,245],{"class":86},[40,424,425],{"class":131}," enumerate",[40,427,377],{"class":90},[40,429,430],{"class":131},"reversed",[40,432,433],{"class":90},"(body)))\n",[40,435,437,440,442,445,448,451,453,456,458,460,462,464],{"class":42,"line":436},7,[40,438,439],{"class":86},"    return",[40,441,277],{"class":90},[40,443,444],{"class":131},"10",[40,446,447],{"class":86}," -",[40,449,450],{"class":90}," total ",[40,452,398],{"class":86},[40,454,455],{"class":131}," 10",[40,457,298],{"class":90},[40,459,398],{"class":86},[40,461,455],{"class":131},[40,463,404],{"class":86},[40,465,466],{"class":90}," check\n",[40,468,470],{"class":42,"line":469},8,[40,471,104],{"emptyLinePlaceholder":103},[40,473,475,478,481,484,486,489,491],{"class":42,"line":474},9,[40,476,477],{"class":90},"sup[",[40,479,480],{"class":50},"\"Barcode OK\"",[40,482,483],{"class":90},"] ",[40,485,113],{"class":86},[40,487,488],{"class":90}," sup[",[40,490,155],{"class":50},[40,492,493],{"class":90},"].map(gtin_valid)\n",[40,495,497,499,501,504,506,508,510,512,515,517,519,521],{"class":42,"line":496},10,[40,498,141],{"class":131},[40,500,152],{"class":90},[40,502,503],{"class":50},"\"Supplier\"",[40,505,122],{"class":90},[40,507,155],{"class":50},[40,509,122],{"class":90},[40,511,480],{"class":50},[40,513,514],{"class":90},"]].to_string(",[40,516,172],{"class":125},[40,518,113],{"class":86},[40,520,177],{"class":131},[40,522,180],{"class":90},[10,524,525,528,529,532,533,536],{},[37,526,527],{},"4006381333931"," is valid; ",[37,530,531],{},"4006381333932"," differs only in its last digit and fails. The barcode with a leading zero, ",[37,534,535],{},"0012345678905",", passes — it would have failed if the column had been read as a number. Reversing the body puts the digit next to the check digit at index 0, where it gets weight 3 — the same rule for every GTIN length. Rejecting codes whose length is wrong or which contain anything other than digits catches truncation and stray characters before the arithmetic.",[538,539,547,548,547,552,547,556,547,563,547,572,547,578,547,640,547,644,547,653,547,656,547,709,547,712,547,778,547,781,547,785,547,787,547,859,547,866,547,870,547,873,547,877,547,882,547,885,547,887],"svg",{"viewBox":540,"role":541,"ariaLabelledBy":542,"xmlns":545,"style":546},"4 0 752 198","img",[543,544],"cd-gtin-t","cd-gtin-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[549,550,551],"title",{"id":543},"Computing an EAN-13 check digit",[553,554,555],"desc",{"id":544},"The twelve body digits of 4006381333931 weighted 1 and 3 alternately from the left, summed to 89; ten minus 9 gives the check digit 1, which matches the last digit.",[557,558],"rect",{"x":559,"y":190,"width":560,"height":561,"fill":562},"4","752","198","#ffffff",[557,564],{"x":565,"y":566,"width":567,"height":568,"rx":285,"fill":569,"stroke":570,"style":571},"20.0","16.0","720.0","108.0","#f0f2f5","var(--line,#cdd5e6)","stroke-width:1.5px",[573,574,347],"text",{"x":575,"y":576,"style":577},"60.0","47.0","font-size:11px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace",[573,579,582,587,590,593,596,598,600,602,604,607,609,611,613,615,617,619,621,623,625,627,629,631,633,636,638],{"x":580,"y":576,"style":581},"82.0","font-size:12.5px;text-anchor:start;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace",[583,584,586],"tspan",{"style":585},"fill:var(--text,#172033);font-weight:400","body",[583,588,589],{"style":585},"   ",[583,591,559],{"style":592},"fill:var(--gold-ink,#7a4e06);font-weight:400",[583,594,595],{"style":585}," ",[583,597,190],{"style":592},[583,599,595],{"style":585},[583,601,190],{"style":592},[583,603,595],{"style":585},[583,605,606],{"style":592},"6",[583,608,595],{"style":585},[583,610,166],{"style":592},[583,612,595],{"style":585},[583,614,280],{"style":592},[583,616,595],{"style":585},[583,618,347],{"style":592},[583,620,595],{"style":585},[583,622,166],{"style":592},[583,624,595],{"style":585},[583,626,166],{"style":592},[583,628,595],{"style":585},[583,630,166],{"style":592},[583,632,595],{"style":585},[583,634,635],{"style":592},"9",[583,637,595],{"style":585},[583,639,166],{"style":592},[573,641,643],{"x":575,"y":642,"style":577},"68.0","2",[645,646],"circle",{"cx":647,"cy":648,"r":649,"fill":650,"stroke":651,"style":652},"36.0","63.5","11.0","#4338ca","none","stroke-width:0px",[573,654,347],{"x":647,"y":642,"style":655},"font-size:12px;font-weight:700;fill:#ffffff;text-anchor:middle",[573,657,658,661,663,665,667,669,671,673,675,677,679,681,683,685,687,689,691,693,695,697,699,701,703,705,707],{"x":580,"y":642,"style":581},[583,659,660],{"style":585},"weight",[583,662,595],{"style":585},[583,664,347],{"style":592},[583,666,595],{"style":585},[583,668,166],{"style":592},[583,670,595],{"style":585},[583,672,347],{"style":592},[583,674,595],{"style":585},[583,676,166],{"style":592},[583,678,595],{"style":585},[583,680,347],{"style":592},[583,682,595],{"style":585},[583,684,166],{"style":592},[583,686,595],{"style":585},[583,688,347],{"style":592},[583,690,595],{"style":585},[583,692,166],{"style":592},[583,694,595],{"style":585},[583,696,347],{"style":592},[583,698,595],{"style":585},[583,700,166],{"style":592},[583,702,595],{"style":585},[583,704,347],{"style":592},[583,706,595],{"style":585},[583,708,166],{"style":592},[573,710,166],{"x":575,"y":711,"style":577},"89.0",[573,713,714,717,720,722,725,727,729,731,733,736,738,740,742,745,747,749,751,753,755,757,759,761,763,765,767,769,771,773,775],{"x":580,"y":711,"style":581},[583,715,716],{"style":585},"sum",[583,718,719],{"style":585},"    ",[583,721,559],{"style":592},[583,723,724],{"style":585},"+",[583,726,190],{"style":592},[583,728,724],{"style":585},[583,730,190],{"style":592},[583,732,724],{"style":585},[583,734,735],{"style":592},"18",[583,737,724],{"style":585},[583,739,166],{"style":592},[583,741,724],{"style":585},[583,743,744],{"style":592},"24",[583,746,724],{"style":585},[583,748,347],{"style":592},[583,750,724],{"style":585},[583,752,635],{"style":592},[583,754,724],{"style":585},[583,756,166],{"style":592},[583,758,724],{"style":585},[583,760,635],{"style":592},[583,762,724],{"style":585},[583,764,635],{"style":592},[583,766,724],{"style":585},[583,768,635],{"style":592},[583,770,595],{"style":585},[583,772,113],{"style":585},[583,774,595],{"style":585},[583,776,777],{"style":592},"89",[573,779,559],{"x":575,"y":780,"style":577},"110.0",[645,782],{"cx":647,"cy":783,"r":649,"fill":784,"stroke":651,"style":652},"105.5","#0b6157",[573,786,643],{"x":647,"y":780,"style":655},[573,788,789,792,795,797,799,801,803,805,807,809,811,813,815,818,820,822,824,826,828,830,832,834,836,839,841,844,846,849,851,855,857],{"x":580,"y":780,"style":581},[583,790,791],{"style":585},"check",[583,793,794],{"style":585},"  ",[583,796,377],{"style":585},[583,798,444],{"style":592},[583,800,595],{"style":585},[583,802,344],{"style":585},[583,804,595],{"style":585},[583,806,777],{"style":592},[583,808,595],{"style":585},[583,810,398],{"style":585},[583,812,595],{"style":585},[583,814,444],{"style":592},[583,816,817],{"style":585},")",[583,819,595],{"style":585},[583,821,398],{"style":585},[583,823,595],{"style":585},[583,825,444],{"style":592},[583,827,595],{"style":585},[583,829,113],{"style":585},[583,831,595],{"style":585},[583,833,347],{"style":592},[583,835,589],{"style":585},[583,837,838],{"style":585},"✓",[583,840,595],{"style":585},[583,842,843],{"style":585},"last",[583,845,595],{"style":585},[583,847,848],{"style":585},"digit",[583,850,595],{"style":585},[583,852,854],{"style":853},"fill:var(--brand-strong,#4338ca);font-weight:700","is",[583,856,595],{"style":585},[583,858,347],{"style":592},[557,860],{"x":565,"y":861,"width":862,"height":863,"rx":444,"fill":864,"stroke":865,"style":571},"138.0","353.0","44.0","#f0f4ff","var(--brand,#5b5cf0)",[645,867],{"cx":868,"cy":869,"r":649,"fill":650,"stroke":651,"style":652},"40.0","160.0",[573,871,347],{"x":868,"y":872,"style":655},"164.5",[573,874,876],{"x":575,"y":872,"style":875},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:start","weights 3 then 1, counted from the right",[557,878],{"x":879,"y":861,"width":862,"height":863,"rx":444,"fill":880,"stroke":881,"style":571},"387.0","#d9f4f1","var(--teal,#0f9488)",[645,883],{"cx":884,"cy":869,"r":649,"fill":784,"stroke":651,"style":652},"407.0",[573,886,643],{"x":884,"y":872,"style":655},[573,888,890],{"x":889,"y":872,"style":875},"427.0","a single wrong digit changes the sum",[25,892,894],{"id":893},"step-3-ibans-with-the-mod-97-check","Step 3 — IBANs with the mod-97 check",[10,896,897],{},"An IBAN is valid when, after moving the first four characters to the end and turning letters into numbers (A = 10, B = 11, … Z = 35), the resulting number leaves a remainder of 1 when divided by 97:",[30,899,901],{"className":77,"code":900,"language":79,"meta":35,"style":35},"IBAN_LENGTH = {\"DE\": 22, \"ES\": 24, \"DK\": 18, \"GB\": 22, \"FR\": 27, \"NL\": 18, \"IT\": 27, \"BE\": 16}\n\ndef iban_valid(value):\n    s = str(value).replace(\" \", \"\").upper()\n    if len(s) \u003C 15 or not s[:2].isalpha() or not s[2:4].isdigit():\n        return False\n    if s[:2] in IBAN_LENGTH and len(s) != IBAN_LENGTH[s[:2]]:\n        return False\n    rearranged = s[4:] + s[:4]\n    number = \"\".join(str(int(ch, 36)) for ch in rearranged)\n    return int(number) % 97 == 1\n\nsup[\"IBAN OK\"] = sup[\"IBAN\"].map(iban_valid)\nprint(sup[[\"Supplier\", \"IBAN\", \"IBAN OK\"]].to_string(index=False))\n",[37,902,903,991,995,1005,1026,1072,1078,1112,1118,1141,1177,1198,1203,1223],{"__ignoreMap":35},[40,904,905,908,911,914,917,920,923,925,928,930,932,934,937,939,941,943,946,948,950,952,955,957,960,962,965,967,969,971,974,976,978,980,983,985,988],{"class":42,"line":43},[40,906,907],{"class":131},"IBAN_LENGTH",[40,909,910],{"class":86}," =",[40,912,913],{"class":90}," {",[40,915,916],{"class":50},"\"DE\"",[40,918,919],{"class":90},": ",[40,921,922],{"class":131},"22",[40,924,122],{"class":90},[40,926,927],{"class":50},"\"ES\"",[40,929,919],{"class":90},[40,931,744],{"class":131},[40,933,122],{"class":90},[40,935,936],{"class":50},"\"DK\"",[40,938,919],{"class":90},[40,940,735],{"class":131},[40,942,122],{"class":90},[40,944,945],{"class":50},"\"GB\"",[40,947,919],{"class":90},[40,949,922],{"class":131},[40,951,122],{"class":90},[40,953,954],{"class":50},"\"FR\"",[40,956,919],{"class":90},[40,958,959],{"class":131},"27",[40,961,122],{"class":90},[40,963,964],{"class":50},"\"NL\"",[40,966,919],{"class":90},[40,968,735],{"class":131},[40,970,122],{"class":90},[40,972,973],{"class":50},"\"IT\"",[40,975,919],{"class":90},[40,977,959],{"class":131},[40,979,122],{"class":90},[40,981,982],{"class":50},"\"BE\"",[40,984,919],{"class":90},[40,986,987],{"class":131},"16",[40,989,990],{"class":90},"}\n",[40,992,993],{"class":42,"line":100},[40,994,104],{"emptyLinePlaceholder":103},[40,996,997,999,1002],{"class":42,"line":107},[40,998,216],{"class":86},[40,1000,1001],{"class":219}," iban_valid",[40,1003,1004],{"class":90},"(value):\n",[40,1006,1007,1010,1012,1014,1017,1019,1021,1023],{"class":42,"line":138},[40,1008,1009],{"class":90},"    s ",[40,1011,113],{"class":86},[40,1013,248],{"class":131},[40,1015,1016],{"class":90},"(value).replace(",[40,1018,315],{"class":50},[40,1020,122],{"class":90},[40,1022,320],{"class":50},[40,1024,1025],{"class":90},").upper()\n",[40,1027,1028,1030,1032,1035,1038,1041,1044,1047,1050,1052,1055,1057,1059,1062,1064,1067,1069],{"class":42,"line":147},[40,1029,262],{"class":86},[40,1031,265],{"class":131},[40,1033,1034],{"class":90},"(s) ",[40,1036,1037],{"class":86},"\u003C",[40,1039,1040],{"class":131}," 15",[40,1042,1043],{"class":86}," or",[40,1045,1046],{"class":86}," not",[40,1048,1049],{"class":90}," s[:",[40,1051,643],{"class":131},[40,1053,1054],{"class":90},"].isalpha() ",[40,1056,301],{"class":86},[40,1058,1046],{"class":86},[40,1060,1061],{"class":90}," s[",[40,1063,643],{"class":131},[40,1065,1066],{"class":90},":",[40,1068,559],{"class":131},[40,1070,1071],{"class":90},"].isdigit():\n",[40,1073,1074,1076],{"class":42,"line":366},[40,1075,328],{"class":86},[40,1077,331],{"class":131},[40,1079,1080,1082,1084,1086,1088,1090,1093,1096,1098,1100,1102,1104,1107,1109],{"class":42,"line":436},[40,1081,262],{"class":86},[40,1083,1049],{"class":90},[40,1085,643],{"class":131},[40,1087,483],{"class":90},[40,1089,245],{"class":86},[40,1091,1092],{"class":131}," IBAN_LENGTH",[40,1094,1095],{"class":86}," and",[40,1097,265],{"class":131},[40,1099,1034],{"class":90},[40,1101,307],{"class":86},[40,1103,1092],{"class":131},[40,1105,1106],{"class":90},"[s[:",[40,1108,643],{"class":131},[40,1110,1111],{"class":90},"]]:\n",[40,1113,1114,1116],{"class":42,"line":469},[40,1115,328],{"class":86},[40,1117,331],{"class":131},[40,1119,1120,1123,1125,1127,1129,1132,1134,1136,1138],{"class":42,"line":474},[40,1121,1122],{"class":90},"    rearranged ",[40,1124,113],{"class":86},[40,1126,1061],{"class":90},[40,1128,559],{"class":131},[40,1130,1131],{"class":90},":] ",[40,1133,724],{"class":86},[40,1135,1049],{"class":90},[40,1137,559],{"class":131},[40,1139,1140],{"class":90},"]\n",[40,1142,1143,1146,1148,1150,1153,1155,1157,1159,1162,1165,1168,1170,1172,1174],{"class":42,"line":496},[40,1144,1145],{"class":90},"    number ",[40,1147,113],{"class":86},[40,1149,233],{"class":50},[40,1151,1152],{"class":90},".join(",[40,1154,132],{"class":131},[40,1156,377],{"class":90},[40,1158,353],{"class":131},[40,1160,1161],{"class":90},"(ch, ",[40,1163,1164],{"class":131},"36",[40,1166,1167],{"class":90},")) ",[40,1169,239],{"class":86},[40,1171,242],{"class":90},[40,1173,245],{"class":86},[40,1175,1176],{"class":90}," rearranged)\n",[40,1178,1180,1182,1185,1188,1190,1193,1195],{"class":42,"line":1179},11,[40,1181,439],{"class":86},[40,1183,1184],{"class":131}," int",[40,1186,1187],{"class":90},"(number) ",[40,1189,398],{"class":86},[40,1191,1192],{"class":131}," 97",[40,1194,404],{"class":86},[40,1196,1197],{"class":131}," 1\n",[40,1199,1201],{"class":42,"line":1200},12,[40,1202,104],{"emptyLinePlaceholder":103},[40,1204,1206,1208,1211,1213,1215,1217,1220],{"class":42,"line":1205},13,[40,1207,477],{"class":90},[40,1209,1210],{"class":50},"\"IBAN OK\"",[40,1212,483],{"class":90},[40,1214,113],{"class":86},[40,1216,488],{"class":90},[40,1218,1219],{"class":50},"\"IBAN\"",[40,1221,1222],{"class":90},"].map(iban_valid)\n",[40,1224,1226,1228,1230,1232,1234,1236,1238,1240,1242,1244,1246,1248],{"class":42,"line":1225},14,[40,1227,141],{"class":131},[40,1229,152],{"class":90},[40,1231,503],{"class":50},[40,1233,122],{"class":90},[40,1235,1219],{"class":50},[40,1237,122],{"class":90},[40,1239,1210],{"class":50},[40,1241,514],{"class":90},[40,1243,172],{"class":125},[40,1245,113],{"class":86},[40,1247,177],{"class":131},[40,1249,180],{"class":90},[10,1251,1252,1255,1256,1259,1260,1263,1264,1259,1267,1270],{},[37,1253,1254],{},"int(ch, 36)"," converts ",[37,1257,1258],{},"\"0\"","–",[37,1261,1262],{},"\"9\""," to 0–9 and ",[37,1265,1266],{},"\"A\"",[37,1268,1269],{},"\"Z\""," to 10–35 in one step. Python integers have no size limit, so the 30-plus-digit number is computed exactly — something a spreadsheet formula cannot do, which is why IBAN checks in Excel need piecewise MOD tricks. Checking the country-specific length catches a dropped digit even in the rare case where the remainder happens to work out. The second German IBAN, one digit different from the first, fails; the British one passes with or without spaces.",[25,1272,1274],{"id":1273},"step-4-the-luhn-algorithm","Step 4 — The Luhn algorithm",[10,1276,1277],{},"Payment card numbers, many loyalty and membership numbers and some national IDs use the Luhn (mod 10) check: double every second digit from the right, subtract 9 from any result above 9, and the total must be a multiple of 10:",[30,1279,1281],{"className":77,"code":1280,"language":79,"meta":35,"style":35},"def luhn_valid(value):\n    digits = str(value).replace(\" \", \"\")\n    if not digits.isdigit() or not 12 \u003C= len(digits) \u003C= 19:\n        return False\n    total = 0\n    for i, d in enumerate(reversed(digits)):\n        n = int(d)\n        if i % 2 == 1:\n            n *= 2\n            if n > 9:\n                n -= 9\n        total += n\n    return total % 10 == 0\n\nsup[\"CardRef OK\"] = sup[\"CardRef\"].map(luhn_valid)\nprint(sup[[\"Supplier\", \"CardRef\", \"CardRef OK\"]].to_string(index=False))\n",[37,1282,1283,1292,1310,1342,1348,1357,1375,1387,1404,1415,1431,1442,1453,1467,1471,1490],{"__ignoreMap":35},[40,1284,1285,1287,1290],{"class":42,"line":43},[40,1286,216],{"class":86},[40,1288,1289],{"class":219}," luhn_valid",[40,1291,1004],{"class":90},[40,1293,1294,1296,1298,1300,1302,1304,1306,1308],{"class":42,"line":100},[40,1295,228],{"class":90},[40,1297,113],{"class":86},[40,1299,248],{"class":131},[40,1301,1016],{"class":90},[40,1303,315],{"class":50},[40,1305,122],{"class":90},[40,1307,320],{"class":50},[40,1309,135],{"class":90},[40,1311,1312,1314,1316,1319,1321,1323,1326,1329,1331,1333,1336,1339],{"class":42,"line":107},[40,1313,262],{"class":86},[40,1315,1046],{"class":86},[40,1317,1318],{"class":90}," digits.isdigit() ",[40,1320,301],{"class":86},[40,1322,1046],{"class":86},[40,1324,1325],{"class":131}," 12",[40,1327,1328],{"class":86}," \u003C=",[40,1330,265],{"class":131},[40,1332,268],{"class":90},[40,1334,1335],{"class":86},"\u003C=",[40,1337,1338],{"class":131}," 19",[40,1340,1341],{"class":90},":\n",[40,1343,1344,1346],{"class":42,"line":138},[40,1345,328],{"class":86},[40,1347,331],{"class":131},[40,1349,1350,1352,1354],{"class":42,"line":147},[40,1351,369],{"class":90},[40,1353,113],{"class":86},[40,1355,1356],{"class":131}," 0\n",[40,1358,1359,1362,1364,1366,1368,1370,1372],{"class":42,"line":366},[40,1360,1361],{"class":86},"    for",[40,1363,420],{"class":90},[40,1365,245],{"class":86},[40,1367,425],{"class":131},[40,1369,377],{"class":90},[40,1371,430],{"class":131},[40,1373,1374],{"class":90},"(digits)):\n",[40,1376,1377,1380,1382,1384],{"class":42,"line":436},[40,1378,1379],{"class":90},"        n ",[40,1381,113],{"class":86},[40,1383,1184],{"class":131},[40,1385,1386],{"class":90},"(d)\n",[40,1388,1389,1392,1394,1396,1398,1400,1402],{"class":42,"line":469},[40,1390,1391],{"class":86},"        if",[40,1393,395],{"class":90},[40,1395,398],{"class":86},[40,1397,401],{"class":131},[40,1399,404],{"class":86},[40,1401,413],{"class":131},[40,1403,1341],{"class":90},[40,1405,1406,1409,1412],{"class":42,"line":474},[40,1407,1408],{"class":90},"            n ",[40,1410,1411],{"class":86},"*=",[40,1413,1414],{"class":131}," 2\n",[40,1416,1417,1420,1423,1426,1429],{"class":42,"line":496},[40,1418,1419],{"class":86},"            if",[40,1421,1422],{"class":90}," n ",[40,1424,1425],{"class":86},">",[40,1427,1428],{"class":131}," 9",[40,1430,1341],{"class":90},[40,1432,1433,1436,1439],{"class":42,"line":1179},[40,1434,1435],{"class":90},"                n ",[40,1437,1438],{"class":86},"-=",[40,1440,1441],{"class":131}," 9\n",[40,1443,1444,1447,1450],{"class":42,"line":1200},[40,1445,1446],{"class":90},"        total ",[40,1448,1449],{"class":86},"+=",[40,1451,1452],{"class":90}," n\n",[40,1454,1455,1457,1459,1461,1463,1465],{"class":42,"line":1205},[40,1456,439],{"class":86},[40,1458,450],{"class":90},[40,1460,398],{"class":86},[40,1462,455],{"class":131},[40,1464,404],{"class":86},[40,1466,1356],{"class":131},[40,1468,1469],{"class":42,"line":1225},[40,1470,104],{"emptyLinePlaceholder":103},[40,1472,1474,1476,1479,1481,1483,1485,1487],{"class":42,"line":1473},15,[40,1475,477],{"class":90},[40,1477,1478],{"class":50},"\"CardRef OK\"",[40,1480,483],{"class":90},[40,1482,113],{"class":86},[40,1484,488],{"class":90},[40,1486,160],{"class":50},[40,1488,1489],{"class":90},"].map(luhn_valid)\n",[40,1491,1493,1495,1497,1499,1501,1503,1505,1507,1509,1511,1513,1515],{"class":42,"line":1492},16,[40,1494,141],{"class":131},[40,1496,152],{"class":90},[40,1498,503],{"class":50},[40,1500,122],{"class":90},[40,1502,160],{"class":50},[40,1504,122],{"class":90},[40,1506,1478],{"class":50},[40,1508,514],{"class":90},[40,1510,172],{"class":125},[40,1512,113],{"class":86},[40,1514,177],{"class":131},[40,1516,180],{"class":90},[10,1518,1519,1520,1523],{},"The standard test numbers pass; ",[37,1521,1522],{},"4539148803436468",", the first number with its last digit changed, fails. Luhn catches every single-digit error and most swaps of adjacent digits — except swaps of 0 and 9, a known blind spot. Never store or process real card numbers in spreadsheets; the check is shown here because the same algorithm validates many non-sensitive reference numbers.",[538,1525,547,1530,547,1533,547,1536,547,1539,547,1543,547,1548,547,1554,547,1557,547,1561,547,1564,547,1568,547,1573,547,1579,547,1581,547,1586,547,1588,547,1597,547,1599,547,1602,547,1605,547,1609,547,1611,547,1615,547,1617,547,1622,547,1624,547,1629,547,1632,547,1636,547,1638,547,1642,547,1644,547,1649,547,1651],{"viewBox":1526,"role":541,"ariaLabelledBy":1527,"xmlns":545,"style":546},"4 0 752 174",[1528,1529],"cd-schemes-t","cd-schemes-d",[549,1531,1532],{"id":1528},"Three check-digit schemes and what they catch",[553,1534,1535],{"id":1529},"GTIN uses weights 3 and 1 modulo 10 and catches single wrong digits and most adjacent swaps. IBAN uses modulo 97 on the rearranged number and catches single errors and swaps. Luhn doubles every second digit modulo 10 and catches single errors and most adjacent swaps except 09 and 90.",[557,1537],{"x":559,"y":190,"width":560,"height":1538,"fill":562},"174",[557,1540],{"x":565,"y":566,"width":1541,"height":868,"rx":190,"fill":562,"stroke":570,"style":1542},"99.4","stroke-width:1px",[557,1544],{"x":1545,"y":566,"width":1546,"height":868,"rx":190,"fill":864,"stroke":865,"style":1547},"119.4","206.9","stroke-width:1.2px",[573,1549,1553],{"x":1550,"y":1551,"style":1552},"222.8","41.0","font-size:13px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","rule",[557,1555],{"x":1556,"y":566,"width":1546,"height":868,"rx":190,"fill":864,"stroke":865,"style":1547},"326.2",[573,1558,1560],{"x":1559,"y":1551,"style":1552},"429.7","single digit wrong",[557,1562],{"x":1563,"y":566,"width":1546,"height":868,"rx":190,"fill":864,"stroke":865,"style":1547},"533.1",[573,1565,1567],{"x":1566,"y":1551,"style":1552},"636.6","adjacent swap",[557,1569],{"x":565,"y":1570,"width":1541,"height":1571,"rx":190,"fill":1572,"stroke":570,"style":1542},"56.0","34.0","#e7ebef",[573,1574,1578],{"x":1575,"y":1576,"style":1577},"32.0","78.0","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:start","GTIN \u002F EAN",[557,1580],{"x":1545,"y":1570,"width":1546,"height":1571,"rx":190,"fill":562,"stroke":570,"style":1542},[573,1582,1585],{"x":1550,"y":1583,"style":1584},"77.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","weights 3·1, mod 10",[557,1587],{"x":1556,"y":1570,"width":1546,"height":1571,"rx":190,"fill":562,"stroke":570,"style":1542},[1589,1590,1592],"g",{"transform":1591},"translate(420.7,64.0) scale(0.750)",[1593,1594],"path",{"d":1595,"fill":651,"stroke":881,"style":1596},"M5 12.5l4.5 4.5L19 7","stroke-width:2.40px;stroke-linecap:round;stroke-linejoin:round",[557,1598],{"x":1563,"y":1570,"width":1546,"height":1571,"rx":190,"fill":562,"stroke":570,"style":1542},[573,1600,1601],{"x":1566,"y":1583,"style":1584},"most",[557,1603],{"x":565,"y":1604,"width":1541,"height":1571,"rx":190,"fill":1572,"stroke":570,"style":1542},"90.0",[573,1606,1608],{"x":1575,"y":1607,"style":1577},"112.0","IBAN",[557,1610],{"x":1545,"y":1604,"width":1546,"height":1571,"rx":190,"fill":562,"stroke":570,"style":1542},[573,1612,1614],{"x":1550,"y":1613,"style":1584},"111.0","rearranged number mod 97 = 1",[557,1616],{"x":1556,"y":1604,"width":1546,"height":1571,"rx":190,"fill":562,"stroke":570,"style":1542},[1589,1618,1620],{"transform":1619},"translate(420.7,98.0) scale(0.750)",[1593,1621],{"d":1595,"fill":651,"stroke":881,"style":1596},[557,1623],{"x":1563,"y":1604,"width":1546,"height":1571,"rx":190,"fill":562,"stroke":570,"style":1542},[1589,1625,1627],{"transform":1626},"translate(627.6,98.0) scale(0.750)",[1593,1628],{"d":1595,"fill":651,"stroke":881,"style":1596},[557,1630],{"x":565,"y":1631,"width":1541,"height":1571,"rx":190,"fill":1572,"stroke":570,"style":1542},"124.0",[573,1633,1635],{"x":1575,"y":1634,"style":1577},"146.0","Luhn",[557,1637],{"x":1545,"y":1631,"width":1546,"height":1571,"rx":190,"fill":562,"stroke":570,"style":1542},[573,1639,1641],{"x":1550,"y":1640,"style":1584},"145.0","double every 2nd digit, mod 10",[557,1643],{"x":1556,"y":1631,"width":1546,"height":1571,"rx":190,"fill":562,"stroke":570,"style":1542},[1589,1645,1647],{"transform":1646},"translate(420.7,132.0) scale(0.750)",[1593,1648],{"d":1595,"fill":651,"stroke":881,"style":1596},[557,1650],{"x":1563,"y":1631,"width":1546,"height":1571,"rx":190,"fill":562,"stroke":570,"style":1542},[573,1652,1653],{"x":1566,"y":1640,"style":1584},"most (not 09↔90)",[25,1655,1657],{"id":1656},"step-5-cross-check-with-python-stdnum","Step 5 — Cross-check with python-stdnum",[10,1659,1660,1661,1663],{},"Hand-written validators are short, but a second opinion from a maintained library is cheap insurance — and ",[37,1662,69],{}," covers hundreds of other formats (VAT numbers, ISBNs, national IDs):",[30,1665,1667],{"className":77,"code":1666,"language":79,"meta":35,"style":35},"from stdnum import ean, iban, luhn\n\nlib = pd.DataFrame({\n    \"Barcode\": sup[\"Barcode\"].map(ean.is_valid),\n    \"IBAN\": sup[\"IBAN\"].map(iban.is_valid),\n    \"CardRef\": sup[\"CardRef\"].map(lambda v: luhn.is_valid(v.replace(\" \", \"\"))),\n})\nmine = sup[[\"Barcode OK\", \"IBAN OK\", \"CardRef OK\"]].set_axis([\"Barcode\", \"IBAN\", \"CardRef\"], axis=1)\nprint(\"hand-written validators agree with python-stdnum:\", mine.equals(lib))\nprint(lib.sum().to_dict(), \"valid of\", len(sup))\n",[37,1668,1669,1682,1686,1696,1709,1721,1748,1753,1797,1809],{"__ignoreMap":35},[40,1670,1671,1674,1677,1679],{"class":42,"line":43},[40,1672,1673],{"class":86},"from",[40,1675,1676],{"class":90}," stdnum ",[40,1678,87],{"class":86},[40,1680,1681],{"class":90}," ean, iban, luhn\n",[40,1683,1684],{"class":42,"line":100},[40,1685,104],{"emptyLinePlaceholder":103},[40,1687,1688,1691,1693],{"class":42,"line":107},[40,1689,1690],{"class":90},"lib ",[40,1692,113],{"class":86},[40,1694,1695],{"class":90}," pd.DataFrame({\n",[40,1697,1698,1701,1704,1706],{"class":42,"line":138},[40,1699,1700],{"class":50},"    \"Barcode\"",[40,1702,1703],{"class":90},": sup[",[40,1705,155],{"class":50},[40,1707,1708],{"class":90},"].map(ean.is_valid),\n",[40,1710,1711,1714,1716,1718],{"class":42,"line":147},[40,1712,1713],{"class":50},"    \"IBAN\"",[40,1715,1703],{"class":90},[40,1717,1219],{"class":50},[40,1719,1720],{"class":90},"].map(iban.is_valid),\n",[40,1722,1723,1726,1728,1730,1733,1736,1739,1741,1743,1745],{"class":42,"line":366},[40,1724,1725],{"class":50},"    \"CardRef\"",[40,1727,1703],{"class":90},[40,1729,160],{"class":50},[40,1731,1732],{"class":90},"].map(",[40,1734,1735],{"class":86},"lambda",[40,1737,1738],{"class":90}," v: luhn.is_valid(v.replace(",[40,1740,315],{"class":50},[40,1742,122],{"class":90},[40,1744,320],{"class":50},[40,1746,1747],{"class":90},"))),\n",[40,1749,1750],{"class":42,"line":436},[40,1751,1752],{"class":90},"})\n",[40,1754,1755,1758,1760,1763,1765,1767,1769,1771,1773,1776,1778,1780,1782,1784,1786,1788,1791,1793,1795],{"class":42,"line":469},[40,1756,1757],{"class":90},"mine ",[40,1759,113],{"class":86},[40,1761,1762],{"class":90}," sup[[",[40,1764,480],{"class":50},[40,1766,122],{"class":90},[40,1768,1210],{"class":50},[40,1770,122],{"class":90},[40,1772,1478],{"class":50},[40,1774,1775],{"class":90},"]].set_axis([",[40,1777,155],{"class":50},[40,1779,122],{"class":90},[40,1781,1219],{"class":50},[40,1783,122],{"class":90},[40,1785,160],{"class":50},[40,1787,350],{"class":90},[40,1789,1790],{"class":125},"axis",[40,1792,113],{"class":86},[40,1794,347],{"class":131},[40,1796,135],{"class":90},[40,1798,1799,1801,1803,1806],{"class":42,"line":474},[40,1800,141],{"class":131},[40,1802,377],{"class":90},[40,1804,1805],{"class":50},"\"hand-written validators agree with python-stdnum:\"",[40,1807,1808],{"class":90},", mine.equals(lib))\n",[40,1810,1811,1813,1816,1819,1821,1824],{"class":42,"line":496},[40,1812,141],{"class":131},[40,1814,1815],{"class":90},"(lib.sum().to_dict(), ",[40,1817,1818],{"class":50},"\"valid of\"",[40,1820,122],{"class":90},[40,1822,1823],{"class":131},"len",[40,1825,1826],{"class":90},"(sup))\n",[10,1828,1829,1830,1833,1834,23],{},"The two agree on every value. ",[37,1831,1832],{},"stdnum.iban"," also knows every country's IBAN length and structure, so in production code using the library is the better choice for IBANs; the hand-written versions are useful where you want no dependency, or need to explain the rule to someone. For format validation without check digits — email addresses, phone numbers — see ",[19,1835,1837],{"href":1836},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fvalidate-email-and-phone-formats-in-excel-data\u002F","Validate Email and Phone Formats in Excel Data",[25,1839,1841],{"id":1840},"step-6-highlight-the-invalid-cells","Step 6 — Highlight the invalid cells",[10,1843,1844],{},"The people who fix the data need to see the failures in their own workbook. Write the sheet with each invalid cell highlighted and a summary column:",[30,1846,1848],{"className":77,"code":1847,"language":79,"meta":35,"style":35},"from openpyxl import load_workbook\nfrom openpyxl.styles import PatternFill, Font\n\nwb = load_workbook(\"suppliers.xlsx\")\nws = wb.active\nbad = PatternFill(\"solid\", fgColor=\"FCE9E9\")\nred = Font(color=\"9C0006\", bold=True)\ncols = {\"IBAN\": \"IBAN OK\", \"Barcode\": \"Barcode OK\", \"CardRef\": \"CardRef OK\"}\nheader = {c.value: c.column for c in ws[1]}\nws.cell(1, ws.max_column + 1, \"Problems\")\nproblem_col = ws.max_column\nfor r, (_, row) in enumerate(sup.iterrows(), start=2):\n    problems = [col for col, flag in cols.items() if not row[flag]]\n    for col in problems:\n        ws.cell(r, header[col]).fill = bad\n        ws.cell(r, header[col]).font = red\n    ws.cell(r, problem_col, \", \".join(problems) or \"ok\")\nwb.save(\"suppliers_checked.xlsx\")\nprint(pd.read_excel(\"suppliers_checked.xlsx\")[[\"Supplier\", \"Problems\"]].to_string(index=False))\n",[37,1849,1850,1862,1874,1878,1892,1902,1927,1957,1990,2015,2036,2046,2069,2096,2108,2118,2128,2147,2158],{"__ignoreMap":35},[40,1851,1852,1854,1857,1859],{"class":42,"line":43},[40,1853,1673],{"class":86},[40,1855,1856],{"class":90}," openpyxl ",[40,1858,87],{"class":86},[40,1860,1861],{"class":90}," load_workbook\n",[40,1863,1864,1866,1869,1871],{"class":42,"line":100},[40,1865,1673],{"class":86},[40,1867,1868],{"class":90}," openpyxl.styles ",[40,1870,87],{"class":86},[40,1872,1873],{"class":90}," PatternFill, Font\n",[40,1875,1876],{"class":42,"line":107},[40,1877,104],{"emptyLinePlaceholder":103},[40,1879,1880,1883,1885,1888,1890],{"class":42,"line":138},[40,1881,1882],{"class":90},"wb ",[40,1884,113],{"class":86},[40,1886,1887],{"class":90}," load_workbook(",[40,1889,119],{"class":50},[40,1891,135],{"class":90},[40,1893,1894,1897,1899],{"class":42,"line":147},[40,1895,1896],{"class":90},"ws ",[40,1898,113],{"class":86},[40,1900,1901],{"class":90}," wb.active\n",[40,1903,1904,1907,1909,1912,1915,1917,1920,1922,1925],{"class":42,"line":366},[40,1905,1906],{"class":90},"bad ",[40,1908,113],{"class":86},[40,1910,1911],{"class":90}," PatternFill(",[40,1913,1914],{"class":50},"\"solid\"",[40,1916,122],{"class":90},[40,1918,1919],{"class":125},"fgColor",[40,1921,113],{"class":86},[40,1923,1924],{"class":50},"\"FCE9E9\"",[40,1926,135],{"class":90},[40,1928,1929,1932,1934,1937,1940,1942,1945,1947,1950,1952,1955],{"class":42,"line":436},[40,1930,1931],{"class":90},"red ",[40,1933,113],{"class":86},[40,1935,1936],{"class":90}," Font(",[40,1938,1939],{"class":125},"color",[40,1941,113],{"class":86},[40,1943,1944],{"class":50},"\"9C0006\"",[40,1946,122],{"class":90},[40,1948,1949],{"class":125},"bold",[40,1951,113],{"class":86},[40,1953,1954],{"class":131},"True",[40,1956,135],{"class":90},[40,1958,1959,1962,1964,1966,1968,1970,1972,1974,1976,1978,1980,1982,1984,1986,1988],{"class":42,"line":469},[40,1960,1961],{"class":90},"cols ",[40,1963,113],{"class":86},[40,1965,913],{"class":90},[40,1967,1219],{"class":50},[40,1969,919],{"class":90},[40,1971,1210],{"class":50},[40,1973,122],{"class":90},[40,1975,155],{"class":50},[40,1977,919],{"class":90},[40,1979,480],{"class":50},[40,1981,122],{"class":90},[40,1983,160],{"class":50},[40,1985,919],{"class":90},[40,1987,1478],{"class":50},[40,1989,990],{"class":90},[40,1991,1992,1995,1997,2000,2002,2005,2007,2010,2012],{"class":42,"line":474},[40,1993,1994],{"class":90},"header ",[40,1996,113],{"class":86},[40,1998,1999],{"class":90}," {c.value: c.column ",[40,2001,239],{"class":86},[40,2003,2004],{"class":90}," c ",[40,2006,245],{"class":86},[40,2008,2009],{"class":90}," ws[",[40,2011,347],{"class":131},[40,2013,2014],{"class":90},"]}\n",[40,2016,2017,2020,2022,2025,2027,2029,2031,2034],{"class":42,"line":496},[40,2018,2019],{"class":90},"ws.cell(",[40,2021,347],{"class":131},[40,2023,2024],{"class":90},", ws.max_column ",[40,2026,724],{"class":86},[40,2028,413],{"class":131},[40,2030,122],{"class":90},[40,2032,2033],{"class":50},"\"Problems\"",[40,2035,135],{"class":90},[40,2037,2038,2041,2043],{"class":42,"line":1179},[40,2039,2040],{"class":90},"problem_col ",[40,2042,113],{"class":86},[40,2044,2045],{"class":90}," ws.max_column\n",[40,2047,2048,2050,2053,2055,2057,2060,2063,2065,2067],{"class":42,"line":1200},[40,2049,239],{"class":86},[40,2051,2052],{"class":90}," r, (_, row) ",[40,2054,245],{"class":86},[40,2056,425],{"class":131},[40,2058,2059],{"class":90},"(sup.iterrows(), ",[40,2061,2062],{"class":125},"start",[40,2064,113],{"class":86},[40,2066,643],{"class":131},[40,2068,323],{"class":90},[40,2070,2071,2074,2076,2079,2081,2084,2086,2089,2091,2093],{"class":42,"line":1205},[40,2072,2073],{"class":90},"    problems ",[40,2075,113],{"class":86},[40,2077,2078],{"class":90}," [col ",[40,2080,239],{"class":86},[40,2082,2083],{"class":90}," col, flag ",[40,2085,245],{"class":86},[40,2087,2088],{"class":90}," cols.items() ",[40,2090,254],{"class":86},[40,2092,1046],{"class":86},[40,2094,2095],{"class":90}," row[flag]]\n",[40,2097,2098,2100,2103,2105],{"class":42,"line":1225},[40,2099,1361],{"class":86},[40,2101,2102],{"class":90}," col ",[40,2104,245],{"class":86},[40,2106,2107],{"class":90}," problems:\n",[40,2109,2110,2113,2115],{"class":42,"line":1473},[40,2111,2112],{"class":90},"        ws.cell(r, header[col]).fill ",[40,2114,113],{"class":86},[40,2116,2117],{"class":90}," bad\n",[40,2119,2120,2123,2125],{"class":42,"line":1492},[40,2121,2122],{"class":90},"        ws.cell(r, header[col]).font ",[40,2124,113],{"class":86},[40,2126,2127],{"class":90}," red\n",[40,2129,2131,2134,2137,2140,2142,2145],{"class":42,"line":2130},17,[40,2132,2133],{"class":90},"    ws.cell(r, problem_col, ",[40,2135,2136],{"class":50},"\", \"",[40,2138,2139],{"class":90},".join(problems) ",[40,2141,301],{"class":86},[40,2143,2144],{"class":50}," \"ok\"",[40,2146,135],{"class":90},[40,2148,2150,2153,2156],{"class":42,"line":2149},18,[40,2151,2152],{"class":90},"wb.save(",[40,2154,2155],{"class":50},"\"suppliers_checked.xlsx\"",[40,2157,135],{"class":90},[40,2159,2161,2163,2166,2168,2171,2173,2175,2177,2179,2181,2183,2185],{"class":42,"line":2160},19,[40,2162,141],{"class":131},[40,2164,2165],{"class":90},"(pd.read_excel(",[40,2167,2155],{"class":50},[40,2169,2170],{"class":90},")[[",[40,2172,503],{"class":50},[40,2174,122],{"class":90},[40,2176,2033],{"class":50},[40,2178,514],{"class":90},[40,2180,172],{"class":125},[40,2182,113],{"class":86},[40,2184,177],{"class":131},[40,2186,180],{"class":90},[10,2188,2189,2190,23],{},"Each failing cell is shaded red and the last column lists the problems per supplier, so the sheet can be filtered to the rows that need attention. The general pattern is covered in ",[19,2191,2193],{"href":2192},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fhighlight-invalid-cells-in-excel-with-python\u002F","Highlight Invalid Cells in Excel with Python",[538,2195,547,2201,547,2204,547,2207,547,2212,547,2216,547,2220,547,2226,547,2230,547,2234,547,2238,547,2242,547,2246,547,2250,547,2253,547,2257,547,2259,547,2263,547,2265,547,2267,547,2269,547,2272,547,2274,547,2277,547,2279,547,2282,547,2284,547,2288,547,2290,547,2293,547,2295,547,2297,547,2299,547,2303,547,2306,547,2309,547,2311,547,2314,547,2316,547,2319,547,2321,547,2324,547,2326,547,2328,547,2330,547,2333,547,2335,547,2338,547,2342,547,2346,547,2348,547,2350,547,2352,547,2355],{"viewBox":2196,"role":541,"ariaLabelledBy":2197,"xmlns":545,"style":2200},"119 0 522 194",[2198,2199],"cd-result-t","cd-result-d","width:100%;max-width:522px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[549,2202,2203],{"id":2198},"The supplier sheet with invalid identifiers highlighted",[553,2205,2206],{"id":2199},"The checked supplier sheet. Müller GmbH and Café Señor SL are ok. Zenith Logistics has an invalid IBAN and barcode. Other suppliers show which identifier failed in the Problems column.",[557,2208],{"x":2209,"y":190,"width":2210,"height":2211,"fill":562},"119","522","194",[557,2213],{"x":2214,"y":566,"width":1575,"height":2215,"rx":190,"fill":1572,"stroke":570,"style":1542},"135.4","24.0",[557,2217],{"x":2218,"y":566,"width":2219,"height":2215,"rx":190,"fill":1572,"stroke":570,"style":1542},"167.4","110.1",[573,2221,2225],{"x":2222,"y":2223,"style":2224},"222.5","33.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[557,2227],{"x":2228,"y":566,"width":2229,"height":2215,"rx":190,"fill":1572,"stroke":570,"style":1542},"277.5","129.7",[573,2231,2233],{"x":2232,"y":2223,"style":2224},"342.3","B",[557,2235],{"x":2236,"y":566,"width":2237,"height":2215,"rx":190,"fill":1572,"stroke":570,"style":1542},"407.2","115.1",[573,2239,2241],{"x":2240,"y":2223,"style":2224},"464.7","C",[557,2243],{"x":2244,"y":566,"width":2245,"height":2215,"rx":190,"fill":1572,"stroke":570,"style":1542},"522.3","102.3",[573,2247,2249],{"x":2248,"y":2223,"style":2224},"573.4","D",[557,2251],{"x":2214,"y":868,"width":1575,"height":2252,"rx":190,"fill":1572,"stroke":570,"style":1542},"28.0",[573,2254,347],{"x":2255,"y":2256,"style":2224},"151.4","59.0",[557,2258],{"x":2218,"y":868,"width":2219,"height":2252,"rx":190,"fill":864,"stroke":865,"style":571},[573,2260,2262],{"x":2222,"y":2256,"style":2261},"font-size:10.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Supplier",[557,2264],{"x":2228,"y":868,"width":2229,"height":2252,"rx":190,"fill":864,"stroke":865,"style":571},[573,2266,1608],{"x":2232,"y":2256,"style":2261},[557,2268],{"x":2236,"y":868,"width":2237,"height":2252,"rx":190,"fill":864,"stroke":865,"style":571},[573,2270,2271],{"x":2240,"y":2256,"style":2261},"Barcode",[557,2273],{"x":2244,"y":868,"width":2245,"height":2252,"rx":190,"fill":864,"stroke":865,"style":571},[573,2275,2276],{"x":2248,"y":2256,"style":2261},"Problems",[557,2278],{"x":2214,"y":642,"width":1575,"height":2252,"rx":190,"fill":1572,"stroke":570,"style":1542},[573,2280,643],{"x":2255,"y":2281,"style":2224},"87.0",[557,2283],{"x":2218,"y":642,"width":2219,"height":2252,"rx":190,"fill":562,"stroke":570,"style":1542},[573,2285,2287],{"x":2222,"y":2281,"style":2286},"font-size:10.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","Müller GmbH",[557,2289],{"x":2228,"y":642,"width":2229,"height":2252,"rx":190,"fill":562,"stroke":570,"style":1542},[573,2291,2292],{"x":2232,"y":2281,"style":2286},"DE89 3704 … 3000",[557,2294],{"x":2236,"y":642,"width":2237,"height":2252,"rx":190,"fill":562,"stroke":570,"style":1542},[573,2296,527],{"x":2240,"y":2281,"style":2286},[557,2298],{"x":2244,"y":642,"width":2245,"height":2252,"rx":190,"fill":880,"stroke":881,"style":571},[573,2300,2302],{"x":2248,"y":2281,"style":2301},"font-size:10.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","ok",[557,2304],{"x":2214,"y":2305,"width":1575,"height":2252,"rx":190,"fill":1572,"stroke":570,"style":1542},"96.0",[573,2307,166],{"x":2255,"y":2308,"style":2224},"115.0",[557,2310],{"x":2218,"y":2305,"width":2219,"height":2252,"rx":190,"fill":562,"stroke":570,"style":1542},[573,2312,2313],{"x":2222,"y":2308,"style":2286},"Café Señor SL",[557,2315],{"x":2228,"y":2305,"width":2229,"height":2252,"rx":190,"fill":562,"stroke":570,"style":1542},[573,2317,2318],{"x":2232,"y":2308,"style":2286},"ES91 2100 … 1332",[557,2320],{"x":2236,"y":2305,"width":2237,"height":2252,"rx":190,"fill":562,"stroke":570,"style":1542},[573,2322,2323],{"x":2240,"y":2308,"style":2286},"8412345678905",[557,2325],{"x":2244,"y":2305,"width":2245,"height":2252,"rx":190,"fill":880,"stroke":881,"style":571},[573,2327,2302],{"x":2248,"y":2308,"style":2301},[557,2329],{"x":2214,"y":1631,"width":1575,"height":2252,"rx":190,"fill":1572,"stroke":570,"style":1542},[573,2331,559],{"x":2255,"y":2332,"style":2224},"143.0",[557,2334],{"x":2218,"y":1631,"width":2219,"height":2252,"rx":190,"fill":562,"stroke":570,"style":1542},[573,2336,2337],{"x":2222,"y":2332,"style":2286},"Zenith Logistics",[557,2339],{"x":2228,"y":1631,"width":2229,"height":2252,"rx":190,"fill":2340,"stroke":2341,"style":571},"#fce9e9","var(--danger,#dc2626)",[573,2343,2345],{"x":2232,"y":2332,"style":2344},"font-size:10.5px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","DE89 3704 … 3001",[557,2347],{"x":2236,"y":1631,"width":2237,"height":2252,"rx":190,"fill":2340,"stroke":2341,"style":571},[573,2349,531],{"x":2240,"y":2332,"style":2344},[557,2351],{"x":2244,"y":1631,"width":2245,"height":2252,"rx":190,"fill":562,"stroke":570,"style":1542},[573,2353,2354],{"x":2248,"y":2332,"style":2286},"IBAN, Barcode",[573,2356,2360],{"x":2357,"y":2358,"style":2359},"380.0","174.0","font-size:12.5px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle","The script prints the full problem list for all six suppliers.",[25,2362,2364],{"id":2363},"common-pitfalls","Common pitfalls",[2366,2367,2368,2376,2382,2388,2394],"ul",{},[2369,2370,2371,2375],"li",{},[2372,2373,2374],"strong",{},"Reading identifiers as numbers."," Leading zeros and digits beyond 15 are lost, and valid codes fail.",[2369,2377,2378,2381],{},[2372,2379,2380],{},"Validating with spaces or dashes."," Strip formatting characters before computing, but reject other characters.",[2369,2383,2384,2387],{},[2372,2385,2386],{},"Confusing valid with real."," A correct check digit only means no typing error was detected; it does not prove the account or product exists.",[2369,2389,2390,2393],{},[2372,2391,2392],{},"Real card numbers in spreadsheets."," Do not store them; use the check only for non-sensitive references.",[2369,2395,2396,2399],{},[2372,2397,2398],{},"Ignoring length rules."," Country-specific IBAN lengths and GTIN lengths catch errors the checksum alone might miss.",[25,2401,2403],{"id":2402},"conclusion","Conclusion",[10,2405,2406,2407,2409],{},"Check digits let a script catch most typing errors in identifiers without any lookup. Read the columns as text, then validate GTIN\u002FEAN barcodes with alternating 3·1 weights modulo 10, IBANs by rearranging, converting letters and testing for a remainder of 1 modulo 97, and Luhn numbers by doubling every second digit. Cross-check against ",[37,2408,69],{},", which covers many more formats, and highlight the failing cells in the workbook so the owners can fix them at the source.",[25,2411,2413],{"id":2412},"frequently-asked-questions","Frequently asked questions",[10,2415,2416,2419],{},[2372,2417,2418],{},"How do I validate an EAN-13 barcode in Python?","\nWeight the first twelve digits alternately 1 and 3 from the left (3 and 1 counted from the right), sum them, and check that (10 - sum % 10) % 10 equals the thirteenth digit. stdnum.ean.is_valid does the same.",[10,2421,2422,2425],{},[2372,2423,2424],{},"How do I check whether an IBAN is valid with Python?","\nRemove spaces, move the first four characters to the end, replace each letter with its number (A=10 to Z=35), and check that the resulting integer modulo 97 equals 1. Also check the country's IBAN length; stdnum.iban.is_valid handles both.",[10,2427,2428,2431],{},[2372,2429,2430],{},"What is the Luhn algorithm?","\nA mod-10 check used by card numbers and many IDs: from the right, double every second digit, subtract 9 from results above 9, add everything up, and the number is valid if the total is divisible by 10.",[10,2433,2434,2437],{},[2372,2435,2436],{},"Why do valid barcodes fail validation after reading the Excel file?","\nThey were read as numbers, so leading zeros were dropped or long values were rounded. Read identifier columns with dtype=str in pd.read_excel.",[25,2439,2441],{"id":2440},"related","Related",[2366,2443,2444,2450,2457,2464],{},[2369,2445,2446,2447,2449],{},"Up one level: ",[19,2448,22],{"href":21}," — checking data before it is used.",[2369,2451,2452,2456],{},[19,2453,2455],{"href":2454},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fvalidate-excel-rows-with-pydantic\u002F","Validate Excel Rows with pydantic Models"," — wrapping such checks in a schema.",[2369,2458,2459,2463],{},[19,2460,2462],{"href":2461},"\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fkeep-leading-zeros-when-reading-excel-with-pandas\u002F","Keep Leading Zeros When Reading Excel with pandas"," — reading identifiers safely.",[2369,2465,2466,2470],{},[19,2467,2469],{"href":2468},"\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fgenerate-qr-codes-and-barcodes-in-excel-with-python\u002F","Generate QR Codes and Barcodes in Excel with Python"," — producing barcodes from validated codes.",[2472,2473,2474],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}",{"title":35,"searchDepth":100,"depth":100,"links":2476},[2477,2478,2479,2480,2481,2482,2483,2484,2485,2486,2487],{"id":27,"depth":100,"text":28},{"id":73,"depth":100,"text":74},{"id":202,"depth":100,"text":203},{"id":893,"depth":100,"text":894},{"id":1273,"depth":100,"text":1274},{"id":1656,"depth":100,"text":1657},{"id":1840,"depth":100,"text":1841},{"id":2363,"depth":100,"text":2364},{"id":2402,"depth":100,"text":2403},{"id":2412,"depth":100,"text":2413},{"id":2440,"depth":100,"text":2441},"2026-10-02","Barcodes, IBANs and many reference numbers carry a check digit that catches most typing errors. Validate them in a spreadsheet with Python: EAN-13 and other GTIN barcodes, IBAN mod-97 checks, the Luhn algorithm used by payment cards and many IDs, reading the columns as text so no digit is lost, cross-checking against python-stdnum, and highlighting invalid cells for the people who fix them.","md",[2492,2494,2496,2498],{"q":2418,"a":2493},"Weight the first twelve digits alternately 1 and 3 from the left (3 and 1 counted from the right), sum them, and check that (10 - sum % 10) % 10 equals the thirteenth digit. stdnum.ean.is_valid does the same.",{"q":2424,"a":2495},"Remove spaces, move the first four characters to the end, replace each letter with its number (A=10 to Z=35), and check that the resulting integer modulo 97 equals 1. Also check the country's IBAN length; stdnum.iban.is_valid handles both.",{"q":2430,"a":2497},"A mod-10 check used by card numbers and many IDs: from the right, double every second digit, subtract 9 from results above 9, add everything up, and the number is valid if the total is divisible by 10.",{"q":2436,"a":2499},"They were read as numbers, so leading zeros were dropped or long values were rounded. Read identifier columns with dtype=str in pd.read_excel.","validate check digits in excel data with python",null,{"breadcrumb":2503},[2504,2507,2510],{"name":2505,"item":2506},"Home","\u002F",{"name":2508,"item":2509},"Advanced Data Transformation and Cleaning for Excel Automation","\u002Fadvanced-data-transformation-and-cleaning\u002F",{"name":22,"item":21},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fvalidate-check-digits-in-excel-data-with-python",{"title":2513,"description":2514},"Validate EAN Barcodes, IBANs and Luhn Check Digits in Excel","Check-digit validation for Excel columns with Python: GTIN\u002FEAN-13 weights 1 and 3, IBAN mod 97 = 1, the Luhn algorithm, reading IDs as text to keep every digit, verifying with python-stdnum, and highlighting invalid rows in the workbook.","validate-check-digits-in-excel-data-with-python","advanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fvalidate-check-digits-in-excel-data-with-python\u002Findex",[2518],"data-validation","how-to","Hvqi8TYGLiIJWd8c_POwltrCW00dfcVYWni83zJcxkY",[2522,2526],{"title":2523,"path":2524,"stem":2525,"children":-1},"Run a Benford's Law Check on Excel Data","\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Frun-a-benfords-law-check-on-excel-data","advanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Frun-a-benfords-law-check-on-excel-data\u002Findex",{"title":2527,"path":2528,"stem":2529,"children":-1},"Validate Dates Fall Within an Expected Period","\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fvalidate-dates-fall-within-an-expected-period","advanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fvalidate-dates-fall-within-an-expected-period\u002Findex",[2531,2533],{"path":2532,"title":2508},"\u002Fadvanced-data-transformation-and-cleaning",{"path":2534,"title":22},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python",[],[2537,2540,2543,2546,2549,2552],{"path":2538,"title":2539,"kind":2519},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fdetect-outliers-in-excel-data-with-pandas","Detect Outliers in Excel Data with pandas",{"path":2541,"title":2542,"kind":2519},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-cells-containing-text-with-openpyxl","Highlight Cells Containing Specific Text with openpyxl",{"path":2544,"title":2545,"kind":2519},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Ffind-near-duplicate-names-within-one-excel-column","Find Near-Duplicate Names Within One Excel Column",{"path":2547,"title":2548,"kind":2519},"\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Fread-dropdown-lists-from-an-existing-workbook","Read Dropdown Lists and Validation Rules from an Existing Workbook",{"path":2550,"title":2551,"kind":2519},"\u002Fadvanced-data-transformation-and-cleaning\u002Fhandling-missing-data-in-excel-reports\u002Ffind-and-report-missing-values-in-an-excel-file","Find and Report Missing Values in an Excel File",{"path":2553,"title":2554,"kind":2519},"\u002Fadvanced-data-transformation-and-cleaning\u002Fhandling-missing-data-in-excel-reports\u002Fflag-rows-with-too-many-missing-values","Flag Rows with Too Many Missing Values",1790972100826]