[{"data":1,"prerenderedAt":2304},["ShallowReactive",2],{"doc:\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fclean-mixed-currency-amounts-into-amount-and-currency-columns":3,"surround:\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fclean-mixed-currency-amounts-into-amount-and-currency-columns":2274,"ancestors:\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fclean-mixed-currency-amounts-into-amount-and-currency-columns":2282,"children:\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fclean-mixed-currency-amounts-into-amount-and-currency-columns":2286,"related:\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fclean-mixed-currency-amounts-into-amount-and-currency-columns":2287},{"id":4,"title":5,"body":6,"dateModified":2239,"datePublished":2239,"description":2240,"extension":2241,"faq":2242,"keyword":2251,"kind":2252,"meta":2253,"navigation":137,"path":2263,"seo":2264,"slug":2267,"stem":2268,"topics":2269,"type":2272,"__hash__":2273},"docs\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fclean-mixed-currency-amounts-into-amount-and-currency-columns\u002Findex.md","Clean Mixed-Currency Amounts into Amount and Currency Columns",{"type":7,"value":8,"toc":2228},"minimark",[9,48,53,81,84,88,101,581,595,599,602,1122,1145,1408,1412,1415,1797,1800,1922,2088,2092,2109,2113,2153,2157,2163,2167,2173,2179,2185,2191,2195,2224],[10,11,12,13,17,18,17,21,17,24,17,27,17,30,33,34,37,38,41,42,47],"p",{},"Expense claims, supplier price lists and spreadsheets assembled from several countries often hold money as text with its currency attached: ",[14,15,16],"code",{},"€1.234,50",", ",[14,19,20],{},"USD 1,200",[14,22,23],{},"1200 GBP",[14,25,26],{},"£950",[14,28,29],{},"CHF 1'250.00",[14,31,32],{},"(45.00) EUR",". Nothing can be summed until each value is split into a number and a currency, and each part has traps. Symbols are ambiguous — ",[14,35,36],{},"$"," could be US, Canadian or Australian dollars. Decimal separators vary — ",[14,39,40],{},"1.234,50"," is one thousand two hundred and thirty-four euros fifty, not one point two. Thousands separators include apostrophes in Switzerland and spaces in France. Negative amounts arrive with minus signs, trailing minus signs or parentheses. This page parses such a column with pandas into a numeric amount and an ISO 4217 currency code, resolves the dollar sign from context, detects the decimal convention from the shape of each number, converts everything to one reporting currency with a rate table, and lists anything it could not read rather than guessing. It belongs to ",[43,44,46],"a",{"href":45},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002F","Cleaning Excel Data with pandas",".",[49,50,52],"h2",{"id":51},"prerequisites","Prerequisites",[54,55,60],"pre",{"className":56,"code":57,"language":58,"meta":59,"style":59},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas openpyxl\n","bash","",[14,61,62],{"__ignoreMap":59},[63,64,67,71,75,78],"span",{"class":65,"line":66},"line",1,[63,68,70],{"class":69},"sMTad","pip",[63,72,74],{"class":73},"srMev"," install",[63,76,77],{"class":73}," pandas",[63,79,80],{"class":73}," openpyxl\n",[10,82,83],{},"The sample is an expense export with a claim ID, the claimant's country and an amount typed with its currency in fourteen different ways, including one that is not an amount at all. The country column is what resolves the ambiguous dollar sign.",[49,85,87],{"id":86},"step-1-recognise-the-currency","Step 1 — Recognise the currency",[10,89,90,91,17,94,97,98,100],{},"Currency is shown either as an ISO code (",[14,92,93],{},"USD",[14,95,96],{},"EUR",") or as a symbol. Codes are unambiguous; symbols map to a code, except ",[14,99,36],{},", whose meaning depends on where the claim came from:",[54,102,106],{"className":103,"code":104,"language":105,"meta":59,"style":59},"language-python shiki shiki-themes github-light github-dark-high-contrast","import re\nimport pandas as pd\n\ndf = pd.read_excel(\"expenses.xlsx\", dtype={\"Amount\": str})\nSYMBOLS = {\"€\": \"EUR\", \"£\": \"GBP\", \"¥\": \"JPY\", \"CHF\": \"CHF\"}\nDOLLAR_BY_COUNTRY = {\"US\": \"USD\", \"CA\": \"CAD\", \"AU\": \"AUD\", \"NZ\": \"NZD\"}\nCODES = {\"USD\", \"EUR\", \"GBP\", \"CHF\", \"JPY\", \"CAD\", \"AUD\", \"NZD\", \"SEK\", \"NOK\", \"DKK\"}\n\ndef currency_of(text, country):\n    code = re.search(r\"\\b([A-Z]{3})\\b\", text)\n    if code and code.group(1) in CODES:\n        return code.group(1), text.replace(code.group(1), \" \")\n    for symbol, iso in SYMBOLS.items():\n        if symbol in text:\n            return iso, text.replace(symbol, \" \")\n    if \"$\" in text:\n        return DOLLAR_BY_COUNTRY.get(country), text.replace(\"$\", \" \")\n    return None, text\n\nprint([currency_of(a, c)[0] for a, c in zip(df[\"Amount\"], df[\"Country\"])])\n","python",[14,107,108,118,132,139,178,230,280,337,342,355,393,423,447,464,478,491,504,524,536,541],{"__ignoreMap":59},[63,109,110,114],{"class":65,"line":66},[63,111,113],{"class":112},"s-kum","import",[63,115,117],{"class":116},"skGVy"," re\n",[63,119,121,123,126,129],{"class":65,"line":120},2,[63,122,113],{"class":112},[63,124,125],{"class":116}," pandas ",[63,127,128],{"class":112},"as",[63,130,131],{"class":116}," pd\n",[63,133,135],{"class":65,"line":134},3,[63,136,138],{"emptyLinePlaceholder":137},true,"\n",[63,140,142,145,148,151,154,156,160,162,165,168,171,175],{"class":65,"line":141},4,[63,143,144],{"class":116},"df ",[63,146,147],{"class":112},"=",[63,149,150],{"class":116}," pd.read_excel(",[63,152,153],{"class":73},"\"expenses.xlsx\"",[63,155,17],{"class":116},[63,157,159],{"class":158},"sa561","dtype",[63,161,147],{"class":112},[63,163,164],{"class":116},"{",[63,166,167],{"class":73},"\"Amount\"",[63,169,170],{"class":116},": ",[63,172,174],{"class":173},"sP0c6","str",[63,176,177],{"class":116},"})\n",[63,179,181,184,187,190,193,195,198,200,203,205,208,210,213,215,218,220,223,225,227],{"class":65,"line":180},5,[63,182,183],{"class":173},"SYMBOLS",[63,185,186],{"class":112}," =",[63,188,189],{"class":116}," {",[63,191,192],{"class":73},"\"€\"",[63,194,170],{"class":116},[63,196,197],{"class":73},"\"EUR\"",[63,199,17],{"class":116},[63,201,202],{"class":73},"\"£\"",[63,204,170],{"class":116},[63,206,207],{"class":73},"\"GBP\"",[63,209,17],{"class":116},[63,211,212],{"class":73},"\"¥\"",[63,214,170],{"class":116},[63,216,217],{"class":73},"\"JPY\"",[63,219,17],{"class":116},[63,221,222],{"class":73},"\"CHF\"",[63,224,170],{"class":116},[63,226,222],{"class":73},[63,228,229],{"class":116},"}\n",[63,231,233,236,238,240,243,245,248,250,253,255,258,260,263,265,268,270,273,275,278],{"class":65,"line":232},6,[63,234,235],{"class":173},"DOLLAR_BY_COUNTRY",[63,237,186],{"class":112},[63,239,189],{"class":116},[63,241,242],{"class":73},"\"US\"",[63,244,170],{"class":116},[63,246,247],{"class":73},"\"USD\"",[63,249,17],{"class":116},[63,251,252],{"class":73},"\"CA\"",[63,254,170],{"class":116},[63,256,257],{"class":73},"\"CAD\"",[63,259,17],{"class":116},[63,261,262],{"class":73},"\"AU\"",[63,264,170],{"class":116},[63,266,267],{"class":73},"\"AUD\"",[63,269,17],{"class":116},[63,271,272],{"class":73},"\"NZ\"",[63,274,170],{"class":116},[63,276,277],{"class":73},"\"NZD\"",[63,279,229],{"class":116},[63,281,283,286,288,290,292,294,296,298,300,302,304,306,308,310,312,314,316,318,320,322,325,327,330,332,335],{"class":65,"line":282},7,[63,284,285],{"class":173},"CODES",[63,287,186],{"class":112},[63,289,189],{"class":116},[63,291,247],{"class":73},[63,293,17],{"class":116},[63,295,197],{"class":73},[63,297,17],{"class":116},[63,299,207],{"class":73},[63,301,17],{"class":116},[63,303,222],{"class":73},[63,305,17],{"class":116},[63,307,217],{"class":73},[63,309,17],{"class":116},[63,311,257],{"class":73},[63,313,17],{"class":116},[63,315,267],{"class":73},[63,317,17],{"class":116},[63,319,277],{"class":73},[63,321,17],{"class":116},[63,323,324],{"class":73},"\"SEK\"",[63,326,17],{"class":116},[63,328,329],{"class":73},"\"NOK\"",[63,331,17],{"class":116},[63,333,334],{"class":73},"\"DKK\"",[63,336,229],{"class":116},[63,338,340],{"class":65,"line":339},8,[63,341,138],{"emptyLinePlaceholder":137},[63,343,345,348,352],{"class":65,"line":344},9,[63,346,347],{"class":112},"def",[63,349,351],{"class":350},"s_Opv"," currency_of",[63,353,354],{"class":116},"(text, country):\n",[63,356,358,361,363,366,369,372,375,379,382,385,388,390],{"class":65,"line":357},10,[63,359,360],{"class":116},"    code ",[63,362,147],{"class":112},[63,364,365],{"class":116}," re.search(",[63,367,368],{"class":112},"r",[63,370,371],{"class":73},"\"",[63,373,374],{"class":173},"\\b([",[63,376,378],{"class":377},"sSjpA","A-Z",[63,380,381],{"class":173},"]",[63,383,384],{"class":112},"{3}",[63,386,387],{"class":173},")\\b",[63,389,371],{"class":73},[63,391,392],{"class":116},", text)\n",[63,394,396,399,402,405,408,411,414,417,420],{"class":65,"line":395},11,[63,397,398],{"class":112},"    if",[63,400,401],{"class":116}," code ",[63,403,404],{"class":112},"and",[63,406,407],{"class":116}," code.group(",[63,409,410],{"class":173},"1",[63,412,413],{"class":116},") ",[63,415,416],{"class":112},"in",[63,418,419],{"class":173}," CODES",[63,421,422],{"class":116},":\n",[63,424,426,429,431,433,436,438,441,444],{"class":65,"line":425},12,[63,427,428],{"class":112},"        return",[63,430,407],{"class":116},[63,432,410],{"class":173},[63,434,435],{"class":116},"), text.replace(code.group(",[63,437,410],{"class":173},[63,439,440],{"class":116},"), ",[63,442,443],{"class":73},"\" \"",[63,445,446],{"class":116},")\n",[63,448,450,453,456,458,461],{"class":65,"line":449},13,[63,451,452],{"class":112},"    for",[63,454,455],{"class":116}," symbol, iso ",[63,457,416],{"class":112},[63,459,460],{"class":173}," SYMBOLS",[63,462,463],{"class":116},".items():\n",[63,465,467,470,473,475],{"class":65,"line":466},14,[63,468,469],{"class":112},"        if",[63,471,472],{"class":116}," symbol ",[63,474,416],{"class":112},[63,476,477],{"class":116}," text:\n",[63,479,481,484,487,489],{"class":65,"line":480},15,[63,482,483],{"class":112},"            return",[63,485,486],{"class":116}," iso, text.replace(symbol, ",[63,488,443],{"class":73},[63,490,446],{"class":116},[63,492,494,496,499,502],{"class":65,"line":493},16,[63,495,398],{"class":112},[63,497,498],{"class":73}," \"$\"",[63,500,501],{"class":112}," in",[63,503,477],{"class":116},[63,505,507,509,512,515,518,520,522],{"class":65,"line":506},17,[63,508,428],{"class":112},[63,510,511],{"class":173}," DOLLAR_BY_COUNTRY",[63,513,514],{"class":116},".get(country), text.replace(",[63,516,517],{"class":73},"\"$\"",[63,519,17],{"class":116},[63,521,443],{"class":73},[63,523,446],{"class":116},[63,525,527,530,533],{"class":65,"line":526},18,[63,528,529],{"class":112},"    return",[63,531,532],{"class":173}," None",[63,534,535],{"class":116},", text\n",[63,537,539],{"class":65,"line":538},19,[63,540,138],{"emptyLinePlaceholder":137},[63,542,544,547,550,553,556,559,562,564,567,570,572,575,578],{"class":65,"line":543},20,[63,545,546],{"class":173},"print",[63,548,549],{"class":116},"([currency_of(a, c)[",[63,551,552],{"class":173},"0",[63,554,555],{"class":116},"] ",[63,557,558],{"class":112},"for",[63,560,561],{"class":116}," a, c ",[63,563,416],{"class":112},[63,565,566],{"class":173}," zip",[63,568,569],{"class":116},"(df[",[63,571,167],{"class":73},[63,573,574],{"class":116},"], df[",[63,576,577],{"class":73},"\"Country\"",[63,579,580],{"class":116},"])])\n",[10,582,583,584,587,588,590,591,594],{},"An ISO code wins if present, so ",[14,585,586],{},"1,000.5 EUR"," from a British claimant is euros, not pounds — people abroad often claim in the local currency, which is exactly why the claimant's country cannot simply be used as the currency. The order of the checks matters for the same reason: codes first, then unambiguous symbols, and context only as a last resort. Symbols map to a single code, and ",[14,589,36],{}," is resolved by the claimant's country — a Canadian's ",[14,592,593],{},"$310.40"," is CAD. When neither a code nor a symbol is present, the currency is unknown and the value goes to review; assuming a default currency silently is how expense reports end up overstated by a factor of 140 when yen are read as dollars.",[49,596,598],{"id":597},"step-2-read-the-number-whatever-its-convention","Step 2 — Read the number, whatever its convention",[10,600,601],{},"With the currency removed, what is left is a number written in one of several conventions. The position of the last separator decides which is the decimal mark:",[54,603,605],{"className":103,"code":604,"language":105,"meta":59,"style":59},"def amount_of(text):\n    s = text.strip()\n    negative = (s.startswith(\"(\") and s.endswith(\")\")) or s.startswith(\"-\") or s.endswith(\"-\")\n    s = re.sub(r\"[()\\s'  -]\", \"\", s)\n    if not re.fullmatch(r\"[\\d.,]+\", s):\n        return None\n    last_dot, last_comma = s.rfind(\".\"), s.rfind(\",\")\n    decimal = \",\" if last_comma > last_dot and len(s) - last_comma - 1 in (1, 2) else \".\"\n    if decimal == \",\":\n        s = s.replace(\".\", \"\").replace(\",\", \".\")\n    else:\n        s = s.replace(\",\", \"\")\n    value = float(s)\n    return -value if negative else value\n\ndef parse(text, country):\n    currency, rest = currency_of(str(text), country)\n    amount = amount_of(rest)\n    status = \"ok\" if currency and amount is not None else (\"unknown currency\" if amount is not None else \"not an amount\")\n    return amount, currency, status\n\nparsed = df.apply(lambda r: pd.Series(parse(r[\"Amount\"], r[\"Country\"]), index=[\"Value\", \"Currency\", \"Status\"]), axis=1)\nresult = pd.concat([df, parsed], axis=1)\nprint(result.to_string(index=False))\n",[14,606,607,617,627,672,709,739,746,767,827,841,868,875,891,904,925,929,938,953,963,1015,1022,1027,1085,1104],{"__ignoreMap":59},[63,608,609,611,614],{"class":65,"line":66},[63,610,347],{"class":112},[63,612,613],{"class":350}," amount_of",[63,615,616],{"class":116},"(text):\n",[63,618,619,622,624],{"class":65,"line":120},[63,620,621],{"class":116},"    s ",[63,623,147],{"class":112},[63,625,626],{"class":116}," text.strip()\n",[63,628,629,632,634,637,640,642,644,647,650,653,656,659,662,664,666,668,670],{"class":65,"line":134},[63,630,631],{"class":116},"    negative ",[63,633,147],{"class":112},[63,635,636],{"class":116}," (s.startswith(",[63,638,639],{"class":73},"\"(\"",[63,641,413],{"class":116},[63,643,404],{"class":112},[63,645,646],{"class":116}," s.endswith(",[63,648,649],{"class":73},"\")\"",[63,651,652],{"class":116},")) ",[63,654,655],{"class":112},"or",[63,657,658],{"class":116}," s.startswith(",[63,660,661],{"class":73},"\"-\"",[63,663,413],{"class":116},[63,665,655],{"class":112},[63,667,646],{"class":116},[63,669,661],{"class":73},[63,671,446],{"class":116},[63,673,674,676,678,681,683,685,688,691,694,697,699,701,703,706],{"class":65,"line":141},[63,675,621],{"class":116},[63,677,147],{"class":112},[63,679,680],{"class":116}," re.sub(",[63,682,368],{"class":112},[63,684,371],{"class":73},[63,686,687],{"class":173},"[",[63,689,690],{"class":377},"()",[63,692,693],{"class":173},"\\s",[63,695,696],{"class":377},"'  -",[63,698,381],{"class":173},[63,700,371],{"class":73},[63,702,17],{"class":116},[63,704,705],{"class":73},"\"\"",[63,707,708],{"class":116},", s)\n",[63,710,711,713,716,719,721,723,726,729,731,734,736],{"class":65,"line":180},[63,712,398],{"class":112},[63,714,715],{"class":112}," not",[63,717,718],{"class":116}," re.fullmatch(",[63,720,368],{"class":112},[63,722,371],{"class":73},[63,724,725],{"class":173},"[\\d",[63,727,728],{"class":377},".,",[63,730,381],{"class":173},[63,732,733],{"class":112},"+",[63,735,371],{"class":73},[63,737,738],{"class":116},", s):\n",[63,740,741,743],{"class":65,"line":232},[63,742,428],{"class":112},[63,744,745],{"class":173}," None\n",[63,747,748,751,753,756,759,762,765],{"class":65,"line":282},[63,749,750],{"class":116},"    last_dot, last_comma ",[63,752,147],{"class":112},[63,754,755],{"class":116}," s.rfind(",[63,757,758],{"class":73},"\".\"",[63,760,761],{"class":116},"), s.rfind(",[63,763,764],{"class":73},"\",\"",[63,766,446],{"class":116},[63,768,769,772,774,777,780,783,786,789,791,794,797,800,802,804,807,809,812,814,816,819,821,824],{"class":65,"line":339},[63,770,771],{"class":116},"    decimal ",[63,773,147],{"class":112},[63,775,776],{"class":73}," \",\"",[63,778,779],{"class":112}," if",[63,781,782],{"class":116}," last_comma ",[63,784,785],{"class":112},">",[63,787,788],{"class":116}," last_dot ",[63,790,404],{"class":112},[63,792,793],{"class":173}," len",[63,795,796],{"class":116},"(s) ",[63,798,799],{"class":112},"-",[63,801,782],{"class":116},[63,803,799],{"class":112},[63,805,806],{"class":173}," 1",[63,808,501],{"class":112},[63,810,811],{"class":116}," (",[63,813,410],{"class":173},[63,815,17],{"class":116},[63,817,818],{"class":173},"2",[63,820,413],{"class":116},[63,822,823],{"class":112},"else",[63,825,826],{"class":73}," \".\"\n",[63,828,829,831,834,837,839],{"class":65,"line":344},[63,830,398],{"class":112},[63,832,833],{"class":116}," decimal ",[63,835,836],{"class":112},"==",[63,838,776],{"class":73},[63,840,422],{"class":116},[63,842,843,846,848,851,853,855,857,860,862,864,866],{"class":65,"line":357},[63,844,845],{"class":116},"        s ",[63,847,147],{"class":112},[63,849,850],{"class":116}," s.replace(",[63,852,758],{"class":73},[63,854,17],{"class":116},[63,856,705],{"class":73},[63,858,859],{"class":116},").replace(",[63,861,764],{"class":73},[63,863,17],{"class":116},[63,865,758],{"class":73},[63,867,446],{"class":116},[63,869,870,873],{"class":65,"line":395},[63,871,872],{"class":112},"    else",[63,874,422],{"class":116},[63,876,877,879,881,883,885,887,889],{"class":65,"line":425},[63,878,845],{"class":116},[63,880,147],{"class":112},[63,882,850],{"class":116},[63,884,764],{"class":73},[63,886,17],{"class":116},[63,888,705],{"class":73},[63,890,446],{"class":116},[63,892,893,896,898,901],{"class":65,"line":449},[63,894,895],{"class":116},"    value ",[63,897,147],{"class":112},[63,899,900],{"class":173}," float",[63,902,903],{"class":116},"(s)\n",[63,905,906,908,911,914,917,920,922],{"class":65,"line":466},[63,907,529],{"class":112},[63,909,910],{"class":112}," -",[63,912,913],{"class":116},"value ",[63,915,916],{"class":112},"if",[63,918,919],{"class":116}," negative ",[63,921,823],{"class":112},[63,923,924],{"class":116}," value\n",[63,926,927],{"class":65,"line":480},[63,928,138],{"emptyLinePlaceholder":137},[63,930,931,933,936],{"class":65,"line":493},[63,932,347],{"class":112},[63,934,935],{"class":350}," parse",[63,937,354],{"class":116},[63,939,940,943,945,948,950],{"class":65,"line":506},[63,941,942],{"class":116},"    currency, rest ",[63,944,147],{"class":112},[63,946,947],{"class":116}," currency_of(",[63,949,174],{"class":173},[63,951,952],{"class":116},"(text), country)\n",[63,954,955,958,960],{"class":65,"line":526},[63,956,957],{"class":116},"    amount ",[63,959,147],{"class":112},[63,961,962],{"class":116}," amount_of(rest)\n",[63,964,965,968,970,973,975,978,980,983,986,988,990,993,995,998,1000,1002,1004,1006,1008,1010,1013],{"class":65,"line":538},[63,966,967],{"class":116},"    status ",[63,969,147],{"class":112},[63,971,972],{"class":73}," \"ok\"",[63,974,779],{"class":112},[63,976,977],{"class":116}," currency ",[63,979,404],{"class":112},[63,981,982],{"class":116}," amount ",[63,984,985],{"class":112},"is",[63,987,715],{"class":112},[63,989,532],{"class":173},[63,991,992],{"class":112}," else",[63,994,811],{"class":116},[63,996,997],{"class":73},"\"unknown currency\"",[63,999,779],{"class":112},[63,1001,982],{"class":116},[63,1003,985],{"class":112},[63,1005,715],{"class":112},[63,1007,532],{"class":173},[63,1009,992],{"class":112},[63,1011,1012],{"class":73}," \"not an amount\"",[63,1014,446],{"class":116},[63,1016,1017,1019],{"class":65,"line":543},[63,1018,529],{"class":112},[63,1020,1021],{"class":116}," amount, currency, status\n",[63,1023,1025],{"class":65,"line":1024},21,[63,1026,138],{"emptyLinePlaceholder":137},[63,1028,1030,1033,1035,1038,1041,1044,1046,1049,1051,1054,1057,1059,1061,1064,1066,1069,1071,1074,1076,1079,1081,1083],{"class":65,"line":1029},22,[63,1031,1032],{"class":116},"parsed ",[63,1034,147],{"class":112},[63,1036,1037],{"class":116}," df.apply(",[63,1039,1040],{"class":112},"lambda",[63,1042,1043],{"class":116}," r: pd.Series(parse(r[",[63,1045,167],{"class":73},[63,1047,1048],{"class":116},"], r[",[63,1050,577],{"class":73},[63,1052,1053],{"class":116},"]), ",[63,1055,1056],{"class":158},"index",[63,1058,147],{"class":112},[63,1060,687],{"class":116},[63,1062,1063],{"class":73},"\"Value\"",[63,1065,17],{"class":116},[63,1067,1068],{"class":73},"\"Currency\"",[63,1070,17],{"class":116},[63,1072,1073],{"class":73},"\"Status\"",[63,1075,1053],{"class":116},[63,1077,1078],{"class":158},"axis",[63,1080,147],{"class":112},[63,1082,410],{"class":173},[63,1084,446],{"class":116},[63,1086,1088,1091,1093,1096,1098,1100,1102],{"class":65,"line":1087},23,[63,1089,1090],{"class":116},"result ",[63,1092,147],{"class":112},[63,1094,1095],{"class":116}," pd.concat([df, parsed], ",[63,1097,1078],{"class":158},[63,1099,147],{"class":112},[63,1101,410],{"class":173},[63,1103,446],{"class":116},[63,1105,1107,1109,1112,1114,1116,1119],{"class":65,"line":1106},24,[63,1108,546],{"class":173},[63,1110,1111],{"class":116},"(result.to_string(",[63,1113,1056],{"class":158},[63,1115,147],{"class":112},[63,1117,1118],{"class":173},"False",[63,1120,1121],{"class":116},"))\n",[10,1123,1124,1125,17,1127,17,1130,1133,1134,17,1137,1140,1141,1144],{},"Apostrophes, ordinary spaces and the narrow and non-breaking spaces French formatting uses are all thousands separators and are removed. Then the rule: if the last separator is a comma followed by one or two digits, the comma is the decimal mark (",[14,1126,40],{},[14,1128,1129],{},"2 450,75",[14,1131,1132],{},"45,00","); otherwise the dot is (",[14,1135,1136],{},"1,250.00",[14,1138,1139],{},"1'250.00",") and commas are thousands separators. A value with only a comma and three digits after it, such as ",[14,1142,1143],{},"¥120,000",", is read as thousands — correct here, and the safer reading for most real data. Parentheses, a leading minus or a trailing minus make the amount negative. Anything left that is not digits and separators — \"about 300 dollars\" — is not an amount, and is reported as such.",[1146,1147,1155,1156,1155,1160,1155,1164,1155,1171,1155,1180,1155,1184,1155,1191,1155,1195,1155,1199,1155,1203,1155,1207,1155,1209,1155,1213,1155,1215,1155,1218,1155,1221,1155,1224,1155,1226,1155,1230,1155,1232,1155,1234,1155,1237,1155,1241,1155,1243,1155,1246,1155,1248,1155,1250,1155,1253,1155,1257,1155,1259,1155,1262,1155,1264,1155,1266,1155,1269,1155,1273,1155,1275,1155,1277,1155,1279,1155,1282,1155,1285,1155,1289,1155,1292,1155,1296,1155,1299,1155,1301,1155,1304,1155,1306,1155,1309,1155,1311,1155,1314,1155,1316,1155,1318,1155,1320,1155,1323,1155,1325,1155,1327,1155,1329,1155,1331,1155,1333,1155,1336,1155,1341,1155,1345,1155,1347,1155,1349,1155,1351,1155,1354,1155,1356,1155,1359,1155,1361,1155,1363,1155,1365,1155,1368,1155,1370,1155,1372,1155,1378,1155,1382,1155,1389,1155,1394,1155,1402],"svg",{"viewBox":1148,"role":1149,"ariaLabelledBy":1150,"xmlns":1153,"style":1154},"87 0 585 220","img",[1151,1152],"cur-parse-t","cur-parse-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:585px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[1157,1158,1159],"title",{"id":1151},"From typed amounts to value and currency",[1161,1162,1163],"desc",{"id":1152},"Amounts typed with symbols, codes and different separators are split into a numeric value and an ISO currency code. The dollar sign is resolved from the claimant's country, a decimal comma is detected from the digits after the last separator, and parentheses make the value negative.",[1165,1166],"rect",{"x":1167,"y":552,"width":1168,"height":1169,"fill":1170},"87","585","220","#ffffff",[1165,1172],{"x":1173,"y":1174,"width":1175,"height":1176,"rx":552,"fill":1177,"stroke":1178,"style":1179},"103.9","40.0","32.0","24.0","#e7ebef","var(--line,#cdd5e6)","stroke-width:1px",[1165,1181],{"x":1182,"y":1174,"width":1183,"height":1176,"rx":552,"fill":1177,"stroke":1178,"style":1179},"135.9","74.1",[1185,1186,1190],"text",{"x":1187,"y":1188,"style":1189},"172.9","57.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[1165,1192],{"x":1193,"y":1174,"width":1194,"height":1176,"rx":552,"fill":1177,"stroke":1178,"style":1179},"210.0","128.9",[1185,1196,1198],{"x":1197,"y":1188,"style":1189},"274.4","B",[1165,1200],{"x":1173,"y":1201,"width":1175,"height":1202,"rx":552,"fill":1177,"stroke":1178,"style":1179},"64.0","28.0",[1185,1204,410],{"x":1205,"y":1206,"style":1189},"119.9","83.0",[1165,1208],{"x":1182,"y":1201,"width":1183,"height":1202,"rx":552,"fill":1170,"stroke":1178,"style":1179},[1185,1210,1212],{"x":1187,"y":1206,"style":1211},"font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Country",[1165,1214],{"x":1193,"y":1201,"width":1194,"height":1202,"rx":552,"fill":1170,"stroke":1178,"style":1179},[1185,1216,1217],{"x":1197,"y":1206,"style":1211},"Amount as typed",[1165,1219],{"x":1173,"y":1220,"width":1175,"height":1202,"rx":552,"fill":1177,"stroke":1178,"style":1179},"92.0",[1185,1222,818],{"x":1205,"y":1223,"style":1189},"111.0",[1165,1225],{"x":1182,"y":1220,"width":1183,"height":1202,"rx":552,"fill":1170,"stroke":1178,"style":1179},[1185,1227,1229],{"x":1187,"y":1223,"style":1228},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","DE",[1165,1231],{"x":1193,"y":1220,"width":1194,"height":1202,"rx":552,"fill":1170,"stroke":1178,"style":1179},[1185,1233,16],{"x":1197,"y":1223,"style":1228},[1165,1235],{"x":1173,"y":1236,"width":1175,"height":1202,"rx":552,"fill":1177,"stroke":1178,"style":1179},"120.0",[1185,1238,1240],{"x":1205,"y":1239,"style":1189},"139.0","3",[1165,1242],{"x":1182,"y":1236,"width":1183,"height":1202,"rx":552,"fill":1170,"stroke":1178,"style":1179},[1185,1244,1245],{"x":1187,"y":1239,"style":1228},"CA",[1165,1247],{"x":1193,"y":1236,"width":1194,"height":1202,"rx":552,"fill":1170,"stroke":1178,"style":1179},[1185,1249,593],{"x":1197,"y":1239,"style":1228},[1165,1251],{"x":1173,"y":1252,"width":1175,"height":1202,"rx":552,"fill":1177,"stroke":1178,"style":1179},"148.0",[1185,1254,1256],{"x":1205,"y":1255,"style":1189},"167.0","4",[1165,1258],{"x":1182,"y":1252,"width":1183,"height":1202,"rx":552,"fill":1170,"stroke":1178,"style":1179},[1185,1260,1261],{"x":1187,"y":1255,"style":1228},"CH",[1165,1263],{"x":1193,"y":1252,"width":1194,"height":1202,"rx":552,"fill":1170,"stroke":1178,"style":1179},[1185,1265,29],{"x":1197,"y":1255,"style":1228},[1165,1267],{"x":1173,"y":1268,"width":1175,"height":1202,"rx":552,"fill":1177,"stroke":1178,"style":1179},"176.0",[1185,1270,1272],{"x":1205,"y":1271,"style":1189},"195.0","5",[1165,1274],{"x":1182,"y":1268,"width":1183,"height":1202,"rx":552,"fill":1170,"stroke":1178,"style":1179},[1185,1276,1229],{"x":1187,"y":1271,"style":1228},[1165,1278],{"x":1193,"y":1268,"width":1194,"height":1202,"rx":552,"fill":1170,"stroke":1178,"style":1179},[1185,1280,1281],{"x":1197,"y":1271,"style":1228},"(45,00) EUR",[1165,1283],{"x":1284,"y":1174,"width":1175,"height":1176,"rx":552,"fill":1177,"stroke":1178,"style":1179},"467.4",[1165,1286],{"x":1287,"y":1174,"width":1288,"height":1176,"rx":552,"fill":1177,"stroke":1178,"style":1179},"499.4","74.9",[1185,1290,1190],{"x":1291,"y":1188,"style":1189},"536.9",[1165,1293],{"x":1294,"y":1174,"width":1295,"height":1176,"rx":552,"fill":1177,"stroke":1178,"style":1179},"574.3","81.8",[1185,1297,1198],{"x":1298,"y":1188,"style":1189},"615.2",[1165,1300],{"x":1284,"y":1201,"width":1175,"height":1202,"rx":552,"fill":1177,"stroke":1178,"style":1179},[1185,1302,410],{"x":1303,"y":1206,"style":1189},"483.4",[1165,1305],{"x":1287,"y":1201,"width":1288,"height":1202,"rx":552,"fill":1170,"stroke":1178,"style":1179},[1185,1307,1308],{"x":1291,"y":1206,"style":1211},"Value",[1165,1310],{"x":1294,"y":1201,"width":1295,"height":1202,"rx":552,"fill":1170,"stroke":1178,"style":1179},[1185,1312,1313],{"x":1298,"y":1206,"style":1211},"Currency",[1165,1315],{"x":1284,"y":1220,"width":1175,"height":1202,"rx":552,"fill":1177,"stroke":1178,"style":1179},[1185,1317,818],{"x":1303,"y":1223,"style":1189},[1165,1319],{"x":1287,"y":1220,"width":1288,"height":1202,"rx":552,"fill":1170,"stroke":1178,"style":1179},[1185,1321,1322],{"x":1291,"y":1223,"style":1228},"1234.50",[1165,1324],{"x":1294,"y":1220,"width":1295,"height":1202,"rx":552,"fill":1170,"stroke":1178,"style":1179},[1185,1326,96],{"x":1298,"y":1223,"style":1228},[1165,1328],{"x":1284,"y":1236,"width":1175,"height":1202,"rx":552,"fill":1177,"stroke":1178,"style":1179},[1185,1330,1240],{"x":1303,"y":1239,"style":1189},[1165,1332],{"x":1287,"y":1236,"width":1288,"height":1202,"rx":552,"fill":1170,"stroke":1178,"style":1179},[1185,1334,1335],{"x":1291,"y":1239,"style":1228},"310.40",[1165,1337],{"x":1294,"y":1236,"width":1295,"height":1202,"rx":552,"fill":1338,"stroke":1339,"style":1340},"#fdefd8","var(--gold,#b4740a)","stroke-width:1.5px",[1185,1342,1344],{"x":1298,"y":1239,"style":1343},"font-size:12px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","CAD",[1165,1346],{"x":1284,"y":1252,"width":1175,"height":1202,"rx":552,"fill":1177,"stroke":1178,"style":1179},[1185,1348,1256],{"x":1303,"y":1255,"style":1189},[1165,1350],{"x":1287,"y":1252,"width":1288,"height":1202,"rx":552,"fill":1170,"stroke":1178,"style":1179},[1185,1352,1353],{"x":1291,"y":1255,"style":1228},"1250.00",[1165,1355],{"x":1294,"y":1252,"width":1295,"height":1202,"rx":552,"fill":1170,"stroke":1178,"style":1179},[1185,1357,1358],{"x":1298,"y":1255,"style":1228},"CHF",[1165,1360],{"x":1284,"y":1268,"width":1175,"height":1202,"rx":552,"fill":1177,"stroke":1178,"style":1179},[1185,1362,1272],{"x":1303,"y":1271,"style":1189},[1165,1364],{"x":1287,"y":1268,"width":1288,"height":1202,"rx":552,"fill":1338,"stroke":1339,"style":1340},[1185,1366,1367],{"x":1291,"y":1271,"style":1343},"-45.00",[1165,1369],{"x":1294,"y":1268,"width":1295,"height":1202,"rx":552,"fill":1170,"stroke":1178,"style":1179},[1185,1371,96],{"x":1298,"y":1271,"style":1228},[1185,1373,1377],{"x":1374,"y":1375,"style":1376},"221.4","29.0","font-size:12.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","before",[1185,1379,1381],{"x":1380,"y":1375,"style":1376},"561.8","after",[65,1383],{"x1":1384,"y1":1385,"x2":1386,"y2":1385,"stroke":1387,"style":1388},"348.8","122.0","453.4","var(--brand,#5b5cf0)","stroke-width:2px",[1390,1391],"polygon",{"points":1392,"fill":1393},"457.4,122.0 448.4,127.0 448.4,117.0","#5b5cf0",[1165,1395],{"x":1396,"y":1397,"width":1398,"height":1399,"rx":1400,"fill":1170,"stroke":1178,"style":1401},"367.7","89.0","70.9","22.0","11","stroke-width:1.2px",[1185,1403,1407],{"x":1404,"y":1405,"style":1406},"403.1","104.0","font-size:11.5px;font-weight:400;fill:var(--brand-strong,#4338ca);text-anchor:middle;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace","parse()",[49,1409,1411],{"id":1410},"step-3-convert-to-a-reporting-currency-and-review-the-rest","Step 3 — Convert to a reporting currency, and review the rest",[10,1413,1414],{},"Once each row has a value and a code, converting to one currency is a lookup:",[54,1416,1418],{"className":103,"code":1417,"language":105,"meta":59,"style":59},"RATES_TO_GBP = {\"GBP\": 1.0, \"EUR\": 0.85, \"USD\": 0.76, \"CAD\": 0.55, \"AUD\": 0.50, \"CHF\": 0.94, \"JPY\": 0.0051}\nok = result[result[\"Status\"] == \"ok\"].copy()\nok[\"GBP\"] = (ok[\"Value\"] * ok[\"Currency\"].map(RATES_TO_GBP)).round(2)\nreview = result[result[\"Status\"] != \"ok\"]\nprint(ok[[\"Claim\", \"Value\", \"Currency\", \"GBP\"]].to_string(index=False))\nprint(f\"total GBP {ok['GBP'].sum():,.2f} from {len(ok)} claims; {len(review)} for review:\")\nprint(review[[\"Claim\", \"Amount\", \"Status\"]].to_string(index=False))\n\nwith pd.ExcelWriter(\"expenses_clean.xlsx\", engine=\"openpyxl\") as xw:\n    ok.to_excel(xw, sheet_name=\"Converted\", index=False)\n    review.to_excel(xw, sheet_name=\"Review\", index=False)\n    pd.Series(RATES_TO_GBP, name=\"Rate to GBP\").to_frame().to_excel(xw, sheet_name=\"Rates\")\n",[14,1419,1420,1492,1513,1551,1572,1605,1664,1691,1695,1723,1746,1768],{"__ignoreMap":59},[63,1421,1422,1425,1427,1429,1431,1433,1436,1438,1440,1442,1445,1447,1449,1451,1454,1456,1458,1460,1463,1465,1467,1469,1472,1474,1476,1478,1481,1483,1485,1487,1490],{"class":65,"line":66},[63,1423,1424],{"class":173},"RATES_TO_GBP",[63,1426,186],{"class":112},[63,1428,189],{"class":116},[63,1430,207],{"class":73},[63,1432,170],{"class":116},[63,1434,1435],{"class":173},"1.0",[63,1437,17],{"class":116},[63,1439,197],{"class":73},[63,1441,170],{"class":116},[63,1443,1444],{"class":173},"0.85",[63,1446,17],{"class":116},[63,1448,247],{"class":73},[63,1450,170],{"class":116},[63,1452,1453],{"class":173},"0.76",[63,1455,17],{"class":116},[63,1457,257],{"class":73},[63,1459,170],{"class":116},[63,1461,1462],{"class":173},"0.55",[63,1464,17],{"class":116},[63,1466,267],{"class":73},[63,1468,170],{"class":116},[63,1470,1471],{"class":173},"0.50",[63,1473,17],{"class":116},[63,1475,222],{"class":73},[63,1477,170],{"class":116},[63,1479,1480],{"class":173},"0.94",[63,1482,17],{"class":116},[63,1484,217],{"class":73},[63,1486,170],{"class":116},[63,1488,1489],{"class":173},"0.0051",[63,1491,229],{"class":116},[63,1493,1494,1497,1499,1502,1504,1506,1508,1510],{"class":65,"line":120},[63,1495,1496],{"class":116},"ok ",[63,1498,147],{"class":112},[63,1500,1501],{"class":116}," result[result[",[63,1503,1073],{"class":73},[63,1505,555],{"class":116},[63,1507,836],{"class":112},[63,1509,972],{"class":73},[63,1511,1512],{"class":116},"].copy()\n",[63,1514,1515,1518,1520,1522,1524,1527,1529,1531,1534,1537,1539,1542,1544,1547,1549],{"class":65,"line":134},[63,1516,1517],{"class":116},"ok[",[63,1519,207],{"class":73},[63,1521,555],{"class":116},[63,1523,147],{"class":112},[63,1525,1526],{"class":116}," (ok[",[63,1528,1063],{"class":73},[63,1530,555],{"class":116},[63,1532,1533],{"class":112},"*",[63,1535,1536],{"class":116}," ok[",[63,1538,1068],{"class":73},[63,1540,1541],{"class":116},"].map(",[63,1543,1424],{"class":173},[63,1545,1546],{"class":116},")).round(",[63,1548,818],{"class":173},[63,1550,446],{"class":116},[63,1552,1553,1556,1558,1560,1562,1564,1567,1569],{"class":65,"line":141},[63,1554,1555],{"class":116},"review ",[63,1557,147],{"class":112},[63,1559,1501],{"class":116},[63,1561,1073],{"class":73},[63,1563,555],{"class":116},[63,1565,1566],{"class":112},"!=",[63,1568,972],{"class":73},[63,1570,1571],{"class":116},"]\n",[63,1573,1574,1576,1579,1582,1584,1586,1588,1590,1592,1594,1597,1599,1601,1603],{"class":65,"line":180},[63,1575,546],{"class":173},[63,1577,1578],{"class":116},"(ok[[",[63,1580,1581],{"class":73},"\"Claim\"",[63,1583,17],{"class":116},[63,1585,1063],{"class":73},[63,1587,17],{"class":116},[63,1589,1068],{"class":73},[63,1591,17],{"class":116},[63,1593,207],{"class":73},[63,1595,1596],{"class":116},"]].to_string(",[63,1598,1056],{"class":158},[63,1600,147],{"class":112},[63,1602,1118],{"class":173},[63,1604,1121],{"class":116},[63,1606,1607,1609,1612,1615,1618,1620,1622,1625,1628,1631,1634,1637,1639,1642,1645,1647,1650,1652,1654,1657,1659,1662],{"class":65,"line":232},[63,1608,546],{"class":173},[63,1610,1611],{"class":116},"(",[63,1613,1614],{"class":112},"f",[63,1616,1617],{"class":73},"\"total GBP ",[63,1619,164],{"class":377},[63,1621,1517],{"class":116},[63,1623,1624],{"class":73},"'GBP'",[63,1626,1627],{"class":116},"].sum()",[63,1629,1630],{"class":112},":,.2f",[63,1632,1633],{"class":377},"}",[63,1635,1636],{"class":73}," from ",[63,1638,164],{"class":377},[63,1640,1641],{"class":173},"len",[63,1643,1644],{"class":116},"(ok)",[63,1646,1633],{"class":377},[63,1648,1649],{"class":73}," claims; ",[63,1651,164],{"class":377},[63,1653,1641],{"class":173},[63,1655,1656],{"class":116},"(review)",[63,1658,1633],{"class":377},[63,1660,1661],{"class":73}," for review:\"",[63,1663,446],{"class":116},[63,1665,1666,1668,1671,1673,1675,1677,1679,1681,1683,1685,1687,1689],{"class":65,"line":282},[63,1667,546],{"class":173},[63,1669,1670],{"class":116},"(review[[",[63,1672,1581],{"class":73},[63,1674,17],{"class":116},[63,1676,167],{"class":73},[63,1678,17],{"class":116},[63,1680,1073],{"class":73},[63,1682,1596],{"class":116},[63,1684,1056],{"class":158},[63,1686,147],{"class":112},[63,1688,1118],{"class":173},[63,1690,1121],{"class":116},[63,1692,1693],{"class":65,"line":339},[63,1694,138],{"emptyLinePlaceholder":137},[63,1696,1697,1700,1703,1706,1708,1711,1713,1716,1718,1720],{"class":65,"line":344},[63,1698,1699],{"class":112},"with",[63,1701,1702],{"class":116}," pd.ExcelWriter(",[63,1704,1705],{"class":73},"\"expenses_clean.xlsx\"",[63,1707,17],{"class":116},[63,1709,1710],{"class":158},"engine",[63,1712,147],{"class":112},[63,1714,1715],{"class":73},"\"openpyxl\"",[63,1717,413],{"class":116},[63,1719,128],{"class":112},[63,1721,1722],{"class":116}," xw:\n",[63,1724,1725,1728,1731,1733,1736,1738,1740,1742,1744],{"class":65,"line":357},[63,1726,1727],{"class":116},"    ok.to_excel(xw, ",[63,1729,1730],{"class":158},"sheet_name",[63,1732,147],{"class":112},[63,1734,1735],{"class":73},"\"Converted\"",[63,1737,17],{"class":116},[63,1739,1056],{"class":158},[63,1741,147],{"class":112},[63,1743,1118],{"class":173},[63,1745,446],{"class":116},[63,1747,1748,1751,1753,1755,1758,1760,1762,1764,1766],{"class":65,"line":395},[63,1749,1750],{"class":116},"    review.to_excel(xw, ",[63,1752,1730],{"class":158},[63,1754,147],{"class":112},[63,1756,1757],{"class":73},"\"Review\"",[63,1759,17],{"class":116},[63,1761,1056],{"class":158},[63,1763,147],{"class":112},[63,1765,1118],{"class":173},[63,1767,446],{"class":116},[63,1769,1770,1773,1775,1777,1780,1782,1785,1788,1790,1792,1795],{"class":65,"line":425},[63,1771,1772],{"class":116},"    pd.Series(",[63,1774,1424],{"class":173},[63,1776,17],{"class":116},[63,1778,1779],{"class":158},"name",[63,1781,147],{"class":112},[63,1783,1784],{"class":73},"\"Rate to GBP\"",[63,1786,1787],{"class":116},").to_frame().to_excel(xw, ",[63,1789,1730],{"class":158},[63,1791,147],{"class":112},[63,1793,1794],{"class":73},"\"Rates\"",[63,1796,446],{"class":116},[10,1798,1799],{},"Thirteen of the fourteen claims convert, totalling £9,946.80, and the one that says \"about 300 dollars\" goes to review with its reason. Note the yen claim: ¥120,000 is £612, and had the yen been read as dollars it would have added over £90,000 to the total.",[1146,1801,1155,1807,1155,1810,1155,1813,1155,1817,1155,1822,1155,1827,1155,1832,1155,1837,1155,1840,1155,1844,1155,1849,1155,1854,1155,1857,1155,1860,1155,1863,1155,1867,1155,1870,1155,1873,1155,1876,1155,1881,1155,1883,1155,1887,1155,1890,1155,1895,1155,1898,1155,1901,1155,1904,1155,1908,1155,1911,1155,1915,1155,1918],{"viewBox":1802,"role":1149,"ariaLabelledBy":1803,"xmlns":1153,"style":1806},"4 0 744 300",[1804,1805],"cur-total-t","cur-total-d","width:100%;max-width:744px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[1157,1808,1809],{"id":1804},"The converted claims by original currency",[1161,1811,1812],{"id":1805},"In pounds, euro claims total 3,944.63, sterling 2,137.50, US dollars 1,862.00, Swiss francs 1,175.00, yen 612.00, Canadian dollars 170.72 and Australian dollars 44.95, for a total of 9,946.80.",[1165,1814],{"x":1256,"y":552,"width":1815,"height":1816,"fill":1170},"744","300",[1165,1818],{"x":1819,"y":1820,"width":1188,"height":1202,"rx":1821,"fill":1177,"stroke":1178,"style":1179},"20.0","16.0","7",[1185,1823,96],{"x":1824,"y":1825,"style":1826},"48.5","34.5","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle",[1165,1828],{"x":1829,"y":1820,"width":1830,"height":1202,"rx":1821,"fill":1831,"stroke":1387,"style":1340},"87.0","570.9","#f0f4ff",[1185,1833,1836],{"x":1834,"y":1825,"style":1835},"665.9","font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:start","£3,944.63",[1165,1838],{"x":1819,"y":1839,"width":1188,"height":1202,"rx":1821,"fill":1177,"stroke":1178,"style":1179},"56.0",[1185,1841,1843],{"x":1824,"y":1842,"style":1826},"74.5","GBP",[1165,1845],{"x":1829,"y":1839,"width":1846,"height":1202,"rx":1821,"fill":1847,"stroke":1848,"style":1340},"309.3","#d9f4f1","var(--teal,#0f9488)",[1185,1850,1853],{"x":1851,"y":1842,"style":1852},"404.3","font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:start","£2,137.50",[1165,1855],{"x":1819,"y":1856,"width":1188,"height":1202,"rx":1821,"fill":1177,"stroke":1178,"style":1179},"96.0",[1185,1858,93],{"x":1824,"y":1859,"style":1826},"114.5",[1165,1861],{"x":1829,"y":1856,"width":1862,"height":1202,"rx":1821,"fill":1831,"stroke":1387,"style":1340},"269.5",[1185,1864,1866],{"x":1865,"y":1859,"style":1835},"364.5","£1,862.00",[1165,1868],{"x":1819,"y":1869,"width":1188,"height":1202,"rx":1821,"fill":1177,"stroke":1178,"style":1179},"136.0",[1185,1871,1358],{"x":1824,"y":1872,"style":1826},"154.5",[1165,1874],{"x":1829,"y":1869,"width":1875,"height":1202,"rx":1821,"fill":1177,"stroke":1178,"style":1340},"170.0",[1185,1877,1880],{"x":1878,"y":1872,"style":1879},"265.0","font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:start","£1,175.00",[1165,1882],{"x":1819,"y":1268,"width":1188,"height":1202,"rx":1821,"fill":1177,"stroke":1178,"style":1179},[1185,1884,1886],{"x":1824,"y":1885,"style":1826},"194.5","JPY",[1165,1888],{"x":1829,"y":1268,"width":1889,"height":1202,"rx":1821,"fill":1338,"stroke":1339,"style":1340},"88.6",[1185,1891,1894],{"x":1892,"y":1885,"style":1893},"183.6","font-size:12px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:start","£612.00",[1165,1896],{"x":1819,"y":1897,"width":1188,"height":1202,"rx":1821,"fill":1177,"stroke":1178,"style":1179},"216.0",[1185,1899,1344],{"x":1824,"y":1900,"style":1826},"234.5",[1165,1902],{"x":1829,"y":1897,"width":1903,"height":1202,"rx":1821,"fill":1177,"stroke":1178,"style":1340},"24.7",[1185,1905,1907],{"x":1906,"y":1900,"style":1879},"119.7","£170.72",[1165,1909],{"x":1819,"y":1910,"width":1188,"height":1202,"rx":1821,"fill":1177,"stroke":1178,"style":1179},"256.0",[1185,1912,1914],{"x":1824,"y":1913,"style":1826},"274.5","AUD",[1165,1916],{"x":1829,"y":1910,"width":1917,"height":1202,"rx":1821,"fill":1177,"stroke":1178,"style":1340},"6.5",[1185,1919,1921],{"x":1920,"y":1913,"style":1879},"101.5","£44.95",[1146,1923,1155,1929,1155,1932,1155,1935,1155,1939,1155,1944,1155,1955,1155,1961,1155,1966,1155,1971,1155,1974,1155,1977,1155,1984,1155,1990,1155,1993,1155,1996,1155,2000,1155,2004,1155,2007,1155,2010,1155,2017,1155,2022,1155,2025,1155,2028,1155,2031,1155,2035,1155,2038,1155,2041,1155,2048,1155,2054,1155,2058,1155,2061,1155,2065,1155,2068,1155,2071,1155,2077,1155,2081,1155,2085],{"viewBox":1924,"role":1149,"ariaLabelledBy":1925,"xmlns":1153,"style":1928},"4 0 752 160",[1926,1927],"cur-flow-t","cur-flow-d","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[1157,1930,1931],{"id":1926},"Cleaning a mixed-currency column",[1161,1933,1934],{"id":1927},"Read the column as text, find an ISO code or a symbol and resolve the dollar sign by country, strip separators and detect the decimal mark, apply the sign, convert to the reporting currency with a rate table, and send unreadable values to a review sheet.",[1165,1936],{"x":1256,"y":552,"width":1937,"height":1938,"fill":1170},"752","160",[1165,1940],{"x":1819,"y":1820,"width":1941,"height":1942,"rx":1943,"fill":1177,"stroke":1178,"style":1388},"115.2","128.0","12",[1945,1946,1948],"g",{"transform":1947},"translate(65.6,46.5) scale(1.000)",[1949,1950],"path",{"d":1951,"fill":1952,"stroke":1953,"style":1954},"M3 5h18v14H3z M3 10h18 M3 15h18 M9 5v14","none","var(--text,#172033)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[1185,1956,1960],{"x":1957,"y":1958,"style":1959},"77.6","93.0","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Read as text",[1185,1962,1965],{"x":1957,"y":1963,"style":1964},"112.5","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","dtype=str",[65,1967],{"x1":1968,"y1":1969,"x2":1970,"y2":1969,"stroke":1387,"style":1388},"140.2","80.0","162.2",[1390,1972],{"points":1973,"fill":1393},"166.2,80.0 157.2,85.0 157.2,75.0",[1165,1975],{"x":1976,"y":1820,"width":1941,"height":1942,"rx":1943,"fill":1831,"stroke":1387,"style":1388},"171.2",[1945,1978,1980],{"transform":1979},"translate(216.8,29.0) scale(1.000)",[1949,1981],{"d":1982,"fill":1952,"stroke":1983,"style":1954},"M11 4a7 7 0 1 0 .01 0z M16 16l5 5","var(--brand-strong,#4338ca)",[1185,1985,1989],{"x":1986,"y":1987,"style":1988},"228.8","75.5","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Find",[1185,1991,1992],{"x":1986,"y":1958,"style":1988},"currency",[1185,1994,1995],{"x":1986,"y":1963,"style":1964},"code, symbol, $",[1185,1997,1999],{"x":1986,"y":1998,"style":1964},"130.0","by country",[65,2001],{"x1":2002,"y1":1969,"x2":2003,"y2":1969,"stroke":1387,"style":1388},"291.4","313.4",[1390,2005],{"points":2006,"fill":1393},"317.4,80.0 308.4,85.0 308.4,75.0",[1165,2008],{"x":2009,"y":1820,"width":1941,"height":1942,"rx":1943,"fill":1338,"stroke":1339,"style":1388},"322.4",[1945,2011,2013],{"transform":2012},"translate(368.0,29.0) scale(1.000)",[1949,2014],{"d":2015,"fill":1952,"stroke":2016,"style":1954},"M5 9h14 M4 15h14 M10 4l-2 16 M16 4l-2 16","var(--gold-ink,#7a4e06)",[1185,2018,2021],{"x":2019,"y":1987,"style":2020},"380.0","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Read the",[1185,2023,2024],{"x":2019,"y":1958,"style":2020},"number",[1185,2026,2027],{"x":2019,"y":1963,"style":1964},"decimal comma",[1185,2029,2030],{"x":2019,"y":1998,"style":1964},"or dot",[65,2032],{"x1":2033,"y1":1969,"x2":2034,"y2":1969,"stroke":1387,"style":1388},"442.6","464.6",[1390,2036],{"points":2037,"fill":1393},"468.6,80.0 459.6,85.0 459.6,75.0",[1165,2039],{"x":2040,"y":1820,"width":1941,"height":1942,"rx":1943,"fill":1847,"stroke":1848,"style":1388},"473.6",[1945,2042,2044],{"transform":2043},"translate(519.2,37.8) scale(1.000)",[1949,2045],{"d":2046,"fill":1952,"stroke":2047,"style":1954},"M20 11a8 8 0 1 0-2.3 5.7 M20 4v7h-7","var(--teal-ink,#0b6157)",[1185,2049,2053],{"x":2050,"y":2051,"style":2052},"531.2","84.2","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Convert",[1185,2055,2057],{"x":2050,"y":2056,"style":1964},"103.8","rate table to",[1185,2059,1843],{"x":2050,"y":2060,"style":1964},"121.2",[65,2062],{"x1":2063,"y1":1969,"x2":2064,"y2":1969,"stroke":1387,"style":1388},"593.8","615.8",[1390,2066],{"points":2067,"fill":1393},"619.8,80.0 610.8,85.0 610.8,75.0",[1165,2069],{"x":2070,"y":1820,"width":1941,"height":1942,"rx":1943,"fill":1177,"stroke":1178,"style":1388},"624.8",[1945,2072,2074],{"transform":2073},"translate(670.4,37.8) scale(1.000)",[1949,2075],{"d":2076,"fill":1952,"stroke":1953,"style":1954},"M12 3.5l9.5 17h-19z M12 10v5 M12 17.8v.4",[1185,2078,2080],{"x":2079,"y":2051,"style":1959},"682.4","Review the",[1185,2082,2084],{"x":2079,"y":2083,"style":1959},"101.8","rest",[1185,2086,2087],{"x":2079,"y":2060,"style":1964},"with reasons",[49,2089,2091],{"id":2090},"edge-cases-worth-deciding-up-front","Edge cases worth deciding up front",[10,2093,2094,2095,2098,2099,2102,2103,2106,2107,47],{},"The decimal rule handles the common cases, but some values are genuinely ambiguous, and it is better to decide how to treat them than to discover the choice later. ",[14,2096,2097],{},"1,234"," with nothing else could be one thousand two hundred and thirty-four or, in a decimal-comma country, one point two three four; the rule reads it as thousands, which matches almost all real amounts, but if your data includes small decimal-comma amounts with three decimals — fuel prices, unit costs — use the claimant's country to decide instead. Currencies without minor units, such as the yen, never have decimals, so ",[14,2100,2101],{},"¥1.500"," is fifteen hundred yen, and a dot there can safely be treated as a thousands separator. A currency code that is not in your list — a claim in Thai baht — should go to review rather than be dropped, which is why the code set is explicit. And symbols shared by several currencies are not limited to the dollar: ",[14,2104,2105],{},"kr"," is Swedish, Norwegian or Danish krone depending on the country, and needs the same treatment as ",[14,2108,36],{},[49,2110,2112],{"id":2111},"common-pitfalls","Common pitfalls",[2114,2115,2116,2126,2135,2141,2147],"ul",{},[2117,2118,2119,2123,2124,47],"li",{},[2120,2121,2122],"strong",{},"Reading the column as numbers."," Text such as \"€1.234,50\" turns into NaN; read with ",[14,2125,1965],{},[2117,2127,2128,2134],{},[2120,2129,2130,2131,2133],{},"Assuming ",[14,2132,36],{}," means US dollars."," Resolve it from the country or a separate column.",[2117,2136,2137,2140],{},[2120,2138,2139],{},"Removing every comma."," It breaks decimal-comma amounts such as \"1.234,50\".",[2117,2142,2143,2146],{},[2120,2144,2145],{},"Defaulting unknown currencies."," Send them to review instead.",[2117,2148,2149,2152],{},[2120,2150,2151],{},"Converting without recording the rates."," Write the rates used next to the result.",[49,2154,2156],{"id":2155},"conclusion","Conclusion",[10,2158,2159,2160,2162],{},"Split mixed-currency text into an ISO currency code and a numeric amount: take an explicit code if present, map symbols to codes and resolve ",[14,2161,36],{}," from the claimant's country, strip apostrophe and space separators, decide the decimal mark from the last separator and the digits after it, and apply parentheses or minus signs. Convert to one reporting currency with a recorded rate table, keep the original text, and put anything unreadable on a review sheet with its reason.",[49,2164,2166],{"id":2165},"frequently-asked-questions","Frequently asked questions",[10,2168,2169,2172],{},[2120,2170,2171],{},"How do I split an amount and its currency into two columns in pandas?","\nSearch each value for an ISO currency code or a currency symbol, map it to a code, remove it from the text, and parse what remains as a number.",[10,2174,2175,2178],{},[2120,2176,2177],{},"How do I convert amounts like 1.234,50 to numbers?","\nIf the last separator is a comma followed by one or two digits, treat it as the decimal mark: remove the dots and replace the comma with a dot before converting.",[10,2180,2181,2184],{},[2120,2182,2183],{},"How can I tell which currency a dollar sign means?","\nUse context, such as the claimant's or supplier's country, to map $ to USD, CAD, AUD or another dollar currency, and flag values where the context is missing.",[10,2186,2187,2190],{},[2120,2188,2189],{},"What should happen to amounts that cannot be parsed?","\nList them on a review sheet with the original text and the reason, rather than converting them to zero or a default currency.",[49,2192,2194],{"id":2193},"related","Related",[2114,2196,2197,2203,2210,2217],{},[2117,2198,2199,2200,2202],{},"Up one level: ",[43,2201,46],{"href":45}," — tidying Excel data.",[2117,2204,2205,2209],{},[43,2206,2208],{"href":2207},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-could-not-convert-string-to-float-in-excel-data\u002F","Fix \"Could Not Convert String to Float\" in Excel Data"," — the general number-cleaning case.",[2117,2211,2212,2216],{},[43,2213,2215],{"href":2214},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fconvert-multi-currency-transactions-with-an-fx-rate-table\u002F","Convert Multi-Currency Transactions with an FX Rate Table"," — dated exchange rates.",[2117,2218,2219,2223],{},[43,2220,2222],{"href":2221},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fapplying-number-and-date-formats-in-excel\u002Fformat-excel-cells-as-currency-with-python\u002F","Format Excel Cells as Currency with Python"," — showing the results.",[2225,2226,2227],"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}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":59,"searchDepth":120,"depth":120,"links":2229},[2230,2231,2232,2233,2234,2235,2236,2237,2238],{"id":51,"depth":120,"text":52},{"id":86,"depth":120,"text":87},{"id":597,"depth":120,"text":598},{"id":1410,"depth":120,"text":1411},{"id":2090,"depth":120,"text":2091},{"id":2111,"depth":120,"text":2112},{"id":2155,"depth":120,"text":2156},{"id":2165,"depth":120,"text":2166},{"id":2193,"depth":120,"text":2194},"2026-10-02","Turn an Excel column of amounts typed with their currency — \"€1.234,50\", \"USD 1,200\", \"1200 GBP\", \"£950\", \"CHF 1'250.00\", \"(45.00) EUR\" — into a numeric amount column and an ISO currency code column with pandas: map symbols and codes, resolve the ambiguous dollar sign, detect decimal commas, keep negative signs and parentheses, convert to one reporting currency, and list what could not be read.","md",[2243,2245,2247,2249],{"q":2171,"a":2244},"Search each value for an ISO currency code or a currency symbol, map it to a code, remove it from the text, and parse what remains as a number.",{"q":2177,"a":2246},"If the last separator is a comma followed by one or two digits, treat it as the decimal mark: remove the dots and replace the comma with a dot before converting.",{"q":2183,"a":2248},"Use context, such as the claimant's or supplier's country, to map $ to USD, CAD, AUD or another dollar currency, and flag values where the context is missing.",{"q":2189,"a":2250},"List them on a review sheet with the original text and the reason, rather than converting them to zero or a default currency.","clean mixed currency amounts amount and currency columns",null,{"breadcrumb":2254},[2255,2258,2261],{"name":2256,"item":2257},"Home","\u002F",{"name":2259,"item":2260},"Advanced Data Transformation and Cleaning for Excel Automation","\u002Fadvanced-data-transformation-and-cleaning\u002F",{"name":2262,"item":45},"Cleaning Excel Data With Pandas: A Production Workflow","\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fclean-mixed-currency-amounts-into-amount-and-currency-columns",{"title":2265,"description":2266},"Split Mixed-Currency Excel Amounts into Amount and Currency","Parse amounts with currency symbols and codes in pandas: symbol and ISO code mapping, ambiguous $, decimal comma detection, apostrophe and space separators, negatives in parentheses, conversion to a base currency and a review list.","clean-mixed-currency-amounts-into-amount-and-currency-columns","advanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fclean-mixed-currency-amounts-into-amount-and-currency-columns\u002Findex",[2270,2271],"data-cleaning","pandas","how-to","zlXwESzw9YdfqOrIvtO-0KesvaxqgTszGodeubInZ04",[2275,2278],{"title":2262,"path":2276,"stem":2277,"children":-1},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas","advanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Findex",{"title":2279,"path":2280,"stem":2281,"children":-1},"Coalesce Several Excel Columns into One with pandas","\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fcoalesce-several-excel-columns-into-one-with-pandas","advanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fcoalesce-several-excel-columns-into-one-with-pandas\u002Findex",[2283,2284],{"path":2276,"title":2262},{"path":2285,"title":2259},"\u002Fadvanced-data-transformation-and-cleaning",[],[2288,2291,2294,2295,2298,2301],{"path":2289,"title":2290,"kind":2272},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Ffind-duplicate-rows-in-excel-with-python","Find Duplicate Rows in Excel with Python",{"path":2292,"title":2293,"kind":2272},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-duplicate-values-in-excel-with-openpyxl","Highlight Duplicate Values in Excel with openpyxl",{"path":2280,"title":2279,"kind":2272},{"path":2296,"title":2297,"kind":2272},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fconvert-currency-strings-to-numbers-with-pandas","Convert Currency Strings Like \"$1,234.56\" and \"(500)\" to Numbers with pandas",{"path":2299,"title":2300,"kind":2272},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fconvert-excel-text-columns-to-numbers-with-pandas","Convert Excel Text Columns to Numbers with pandas",{"path":2302,"title":2303,"kind":2272},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fconvert-percentage-strings-to-numbers-with-pandas","Convert Percentage Strings Like \"12.5%\" to Numbers with pandas",1790972080507]