B Binance · The world's largest crypto exchangeBinance Sign up → AD OKX OKX · A leading global crypto exchangeOKX Sign up → AD
💻 Coding Basics · Lesson 9 / 10

Simple Automation — Spreadsheet Math and Text Cleanup in Code

We combine values, conditions, loops, functions, arrays and strings into small automations you can actually use. You move hand-done tallying and cleanup into code, while building the habit of protecting the original and checking the results yourself.

⏱ About 22 min ✍️ 5 practice questions 🧪 4 code exercises Updated 2026-10-09
🎯 By the end of this lesson you can
  • Explain the criteria for deciding whether a repetitive task is worth turning into code
  • Turn multi-line comma-separated text into an array of objects and compute totals, averages and per-group sums
  • Write functions that remove stray spaces, blank lines and duplicates, and unify phone number and date formats
  • Verify automated results by keeping the original and checking samples by hand

1.What to automate — how to decide

Automation means letting code do the repetitive work a person used to do by hand. It does not have to be a big program. A few dozen lines that add up per-item totals from a weekly sales record, or that fix the spacing and duplicates in a list gathered from several places, is perfectly good automation.

That said, not every job needs to become code. If you do something once and it takes ten minutes, writing and checking the code may take longer. On the other hand, a ten-minute job done every week adds up to 520 minutes a year, about nine hours. The more a task repeats under the same rules, the larger the volume, and the more often mistakes creep in when done by hand, the more automation is worth.

It also matters whether the rule is clear. "Keep only the digits of a phone number and reshape it as 010-0000-0000" is easy to write as code. But a job that needs judgment, such as "make awkward sentences sound natural," is better reviewed by a person or an AI assistant than by code. The idea from Lesson 1 still applies here: if you can write the rule down clearly in words, you can write it as code.

Automation checklist
CriterionQuestion to ask yourselfSigns that point toward automating
RepetitionHow often do I do this?It repeats daily, weekly or monthly
RulesCan I write the processing rules in words?Even the exceptions fit in a few lines
VolumeHow many records at a time?Dozens or more, too many to check by eye
Cost of mistakesHow bad is it if it is wrong?Done by hand, items get missed or mistyped often
ChangeDoes the input format change often?Column order and format stay almost the same
Start by doing it "once by hand, once with code" and checking that the two results match. Only after you have confirmed they match do you start trusting the code.

2.Turning comma-separated text into a table

Data downloaded from a spreadsheet program, or a list someone sends you in a chat, often has one record per line with fields separated by commas. This format is called CSV (Comma-Separated Values). The first line is usually the column names (the header), and the actual records start on the second line.

The steps to turn it into code are simple. First split it into lines with split("\n") from Lesson 7, then split each line into fields with split(","). Next, give each field a name using the objects from Lesson 6, and you have an "array of objects" — a table inside your code. It is a good idea to call trim() first so blank lines at the start or end do not create empty records.

There is one important trap. Every field you get from split is a string. Even if it looks like a number, "10" is a string, so adding it directly joins the text, as we saw in Lesson 2. Convert quantity and price fields with Number() so the math comes out right.

A fictional stationery shop's sales record. The first line is the header, so slice(1) skips it.
const text = `date,item,qty,price
2026-03-01,pencil,10,500
2026-03-01,notebook,3,2000
2026-03-02,pencil,5,500
2026-03-02,eraser,4,300`;

const lines = text.trim().split("\n");
console.log(lines[0].split(","));

const rows = lines.slice(1).map((line) => {
  const c = line.split(",");
  return {
    date: c[0],
    item: c[1],
    qty: Number(c[2]),
    price: Number(c[3]),
  };
});
console.log(rows.length);
console.log(rows[0]);
Output
[ 'date', 'item', 'qty', 'price' ]
4
{ date: '2026-03-01', item: 'pencil', qty: 10, price: 500 }
With strings, + joins text. If non-digit characters are mixed in, Number returns NaN.
const c = "2026-03-01,pencil,10,500".split(",");
console.log(c[2] + c[3]);
console.log(Number(c[2]) * Number(c[3]));
console.log(Number("10pcs"));
Output
10500
5000
NaN

3.Totals, averages and per-group sums

Once you have a table, you get the total with the accumulator pattern from Lesson 4. Set one variable to 0, go through the records one by one, and add. The average is the total divided by the number of records, but if there are zero records you divide by 0 and get NaN, so check that first. If the decimals run long, decide on a rounding place, as in Math.round(x * 10) / 10.

Adding up separately for each group, such as "total per item" or "expenses per department," is called a per-group sum. Create one empty object, and for each record use the group name as the key and add the value. A key you have not seen yet has the value undefined, so the trick is to start from 0 with (sums[key] || 0) + value. It is like doing in a few lines what a spreadsheet's pivot table does.

When the calculation is done, always check one number by hand. In the example below, pencils are 10 × 500 won plus 5 × 500 won, so the total should be 7,500 won. Checking even one group yourself immediately catches mistakes like picking the wrong column or forgetting to convert strings to numbers.

In a single pass, we build the total, the quantity sum and the per-item sums together.
const rows = [
  { item: "pencil", qty: 10, price: 500 },
  { item: "notebook", qty: 3, price: 2000 },
  { item: "pencil", qty: 5, price: 500 },
  { item: "eraser", qty: 4, price: 300 },
];

let total = 0;
let qtySum = 0;
const byItem = {};
for (const r of rows) {
  const amount = r.qty * r.price;
  total += amount;
  qtySum += r.qty;
  byItem[r.item] = (byItem[r.item] || 0) + amount;
}
console.log("Total sales", total);
console.log("Average qty", qtySum / rows.length);
console.log(byItem);
Output
Total sales 14700
Average qty 5.5
{ pencil: 7500, notebook: 6000, eraser: 1200 }
ExampleFrom a fictional team expense record, find the total per department and the department that spent the most.
const text = `dept,amount
Sales,32000
Dev,15000
Admin,9000
Sales,18000
Dev,26000`;

const sums = {};
for (const line of text.split("\n").slice(1)) {
  const [team, money] = line.split(",");
  sums[team] = (sums[team] || 0) + Number(money);
}
console.log(sums);

let best = null;
for (const [team, sum] of Object.entries(sums)) {
  if (best === null || sum > best[1]) {
    best = [team, sum];
  }
}
console.log("Top spender:", best[0]);
Output
{ Sales: 50000, Dev: 41000, Admin: 9000 }
Top spender: Sales
  1. Step 1: Split the text into lines and skip the header.
  2. Step 2: Split each line at the comma to get the department and the amount, and convert the amount with Number. In the code, const [team, money] = … puts the first and second values of the split array into two names, in order (destructuring assignment).
  3. Step 3: Add each amount to an empty object, using the department name as the key.
  4. Step 4: Turn the object into an array of [department, total] pairs with Object.entries, then loop through it and remember the largest value.
  5. Check: Sales should be 32,000 + 18,000 = 50,000 won; confirm the code gives the same.
AnswerSales 50,000 won, Dev 41,000 won, Admin 9,000 won, and the department that spent the most is Sales.

4.Cleaning up text — spaces, blank lines, duplicates

A list typed in by several people usually contains leading and trailing spaces, double spaces, blank lines, and the same person entered twice. They may look identical to you, but to a computer "Alex" and "Alex " are different strings, so without cleanup, removing duplicates and searching do not work properly.

The cleanup rule usually has three steps. Remove leading and trailing spaces with trim(), shrink runs of spaces to a single space with replace(/\s+/g, " "), and drop empty strings with filter. \s+ is a regular expression meaning "one or more whitespace characters," which you got a taste of in Lesson 7. If regular expressions confuse you, put a sample sentence into a regex tester first and see what gets matched.

For removing duplicates, Set is handy. A Set holds each value only once, so spreading it back into an array with [...new Set(array)] drops duplicates while keeping the order in which values first appeared. For values usually treated as case-insensitive, such as email addresses, normalize them with toLowerCase() before removing duplicates. Printing the count before and after cleanup shows at a glance how many records were dropped.

Only after cleanup do "Mary Ann" and "Mary Ann" become the same value and get caught as duplicates.
const raw = [
  "  Alex ",
  "Mary  Ann",
  "Alex",
  "",
  "Jay   ",
  "Mary Ann",
];
const cleaned = raw
  .map((s) => s.trim().replace(/\s+/g, " "))
  .filter((s) => s !== "");
console.log(cleaned);

const unique = [...new Set(cleaned)];
console.log(unique);
console.log(raw.length, "→", unique.length);
Output
[ 'Alex', 'Mary Ann', 'Alex', 'Jay', 'Mary Ann' ]
[ 'Alex', 'Mary Ann', 'Jay' ]
6 → 3
const emails = ["[email protected]", "[email protected] "];
const norm = emails.map((e) => e.trim().toLowerCase());
console.log([...new Set(norm)]);
Output
[ '[email protected]' ]

5.Unifying phone number and date formats

The same phone number can arrive in many shapes, such as 010-1234-5678, 01012345678 or 010 1234 5678. (The examples use the Korean mobile format: 11 digits starting with 01.) The sturdiest way to unify the format is "keep only the digits, then reassemble." replace(/\D/g, "") removes every character that is not a digit. If 11 digits remain and they start with 01, cut them 3-4-4 and insert hyphens.

For values that do not fit the rule, do not force a fix; it is better to return something like null meaning "could not process." That way you can collect just those lines later for a person to check. If automation turns an unknown value into something plausible, wrong data quietly mixes in, and that is harder to find than a mistake made by hand.

Dates come in all sorts too, such as 2026.3.5., 2026/03/05 or 2026-3-15 . Remove spaces and the trailing dot, split on any of ., / or -, then pad the month and day to two digits with padStart(2, "0") to get the 2026-03-05 shape. This shape is convenient because sorting it as text also puts the dates in order. The function below only checks month 1–12 and day 1–31, so it cannot catch a date like February 30. Leave limitations like this in a comment.

These are example numbers. Values with the wrong number of digits are marked null so you can check them separately.
function formatPhone(s) {
  const d = s.replace(/\D/g, "");
  if (d.length !== 11 || !d.startsWith("01")) {
    return null;
  }
  return d.slice(0, 3) + "-" + d.slice(3, 7) +
    "-" + d.slice(7);
}

const inputs = [
  "010-1234-5678",
  "01012345678",
  "010 1234 5678",
  "(010)1234.5678",
  "1234-5678",
];
for (const p of inputs) {
  console.log(p, "→", formatPhone(p));
}
Output
010-1234-5678 → 010-1234-5678
01012345678 → 010-1234-5678
010 1234 5678 → 010-1234-5678
(010)1234.5678 → 010-1234-5678
1234-5678 → null
A format in a different order, like 3/5/2026, puts the wrong value in the year slot and becomes null.
// checks only month 1-12 and day 1-31 (Feb 30 slips through)
function formatDate(s) {
  const t = s.replace(/\s/g, "").replace(/\.$/, "");
  const parts = t.split(/[.\/-]/).map(Number);
  if (parts.length !== 3) return null;
  const y = parts[0], m = parts[1], d = parts[2];
  if (!Number.isInteger(y) || y < 1000) return null;
  if (!(m >= 1 && m <= 12 && d >= 1 && d <= 31)) {
    return null;
  }
  const mm = String(m).padStart(2, "0");
  const dd = String(d).padStart(2, "0");
  return y + "-" + mm + "-" + dd;
}

const dates = [
  "2026.3.5.",
  "2026/03/05",
  " 2026-3-15 ",
  "2026. 12. 1",
  "2026.13.1",
  "3/5/2026",
];
for (const x of dates) {
  console.log(JSON.stringify(x), "→", formatDate(x));
}
Output
"2026.3.5." → 2026-03-05
"2026/03/05" → 2026-03-05
" 2026-3-15 " → 2026-03-15
"2026. 12. 1" → 2026-12-01
"2026.13.1" → null
"3/5/2026" → null

6.Protecting the original and checking the results

The worst accident in automation is overwriting the original so you cannot go back. Make it a rule that code only reads the original and writes results to a new variable or a new file. If you work with files, copy the original somewhere safe before you start, and add a date or "cleaned" to the result file's name to tell them apart. As we saw in Lesson 6, map and filter create new arrays and leave the original array untouched, so they fit this rule well.

Check the results in three ways. First, a count check: print the number of original records, result records and filtered-out records, and see whether they add up. Second, a sample check: pick a few lines from the result and compare them with the original by hand, especially the very first, the very last and any that look odd. Third, a total check: see whether the total from a spreadsheet program matches the total from your code. If you put the text before and after cleanup into a text diff checker, you can see only the changed parts at a glance.

With real CSV files, the simple split(",") in this lesson sometimes breaks. There is a rule that a field containing a comma is wrapped in double quotes, so a single field written as "pencil, blue" gets cut into two. There are also rules for line breaks inside a field and quotes inside quotes. So when you handle real files, open and process them in a spreadsheet program, or use a well-tested library (a parser) that implements the CSV rules properly. This lesson's approach suits simple text whose format you defined yourself.

There should be 4 fields, but it was cut into 5. A simple split knows nothing about the quoting rule.
const line = '2026-03-03,"pencil, blue",2,500';
const cells = line.split(",");
console.log(cells.length);
console.log(cells);
Output
5
[ '2026-03-03', '"pencil', ' blue"', '2', '500' ]
Files saved by some programs end each line with \r\n. Do not throw away odd lines; collect them as "on hold" for a person to review.
const text = "name,amount\r\nAlex,3000\r\n\r\nSam,abc\r\n";
const lines = text.split(/\r?\n/).slice(1);
const ok = [];
const bad = [];
for (const line of lines) {
  if (line.trim() === "") continue;
  const c = line.split(",");
  const n = Number(c[1]);
  if (c.length === 2 && Number.isFinite(n)) {
    ok.push({ name: c[0], amount: n });
  } else {
    bad.push(line);
  }
}
console.log("Processed", ok.length, "On hold", bad.length);
console.log(bad);
Output
Processed 1 On hold 1
[ 'Sam,abc' ]
  • Only read the original; write results to a new variable or new file
  • Check that original count = processed count + on-hold count
  • Pick the first, last and odd-looking lines and compare them by hand
  • Double-check one total another way (a calculator or a spreadsheet program)
  • Handle real CSV files with a spreadsheet program or a well-tested CSV parser

7.Building automation with an AI assistant

Automation code is a good job to hand to an AI coding assistant. To get good results, though, you need to state the input shape, the output you want and the rules for exceptions clearly. "Clean up my CSV" gets far less accurate code than "a function that takes text with the header dept,amount and returns an object of totals per department, and collects lines whose amount is not a number separately."

When you show data to an AI, do not paste in a real customer list or contact details; show just a few lines of fake data in the same shape. Knowing the format is enough to write the code. Run the code you receive on the real data on your own computer, and do the same count, sample and total checks described above.

How to read and test the code you receive is covered in detail in the next lesson, Lesson 10. If you have solved this lesson's exercises yourself, you will spot places in AI-written code where the Number conversion is missing or blank lines are not handled much more easily.

At the top of any automation code, write three comment lines: the input shape, the output shape, and the cases it cannot handle. That becomes the best manual for both you a few months from now and your AI assistant.

📌 Key points

  • Tasks that repeat often, have clear rules, come in volume and are error-prone by hand are automation candidates
  • Split lines with split("\n") and fields with split(","), and convert numeric fields with Number
  • Build per-group sums in an empty object with (sums[key] || 0) + value
  • Do not force-fix values that break the cleanup rules; mark them as null or on hold
  • Protect the original, verify results with count, sample and total checks, and handle real CSV files with a dedicated parser or a spreadsheet program

✍️ Practice questions

Answer first, then open "Answer and explanation".

Q1. If you split "2026-03-01,pencil,10,500".split(",") and add the quantity and price directly with c[2] + c[3], what is the result?

⭕ Correct

❌ Not quite — see the explanation

Answer and explanation
Answer ② "10500"

Every field from split is a string, so + joins them. To calculate, convert them with Number.

Q2. Which of the following is most worth automating?

⭕ Correct

❌ Not quite — see the explanation

Answer and explanation
Answer ② Totaling per-item sales from a weekly record of several hundred lines

It repeats often, has clear rules and comes in volume. Polishing tone or choosing a venue needs judgment.

Q3. How many fields does 'a,"b, c",d'.split(",") produce?

⭕ Correct

❌ Not quite — see the explanation

Answer and explanation
Answer ③ 4

A simple split does not know the quoting rule, so it also cuts at the comma inside the field, giving 4. Handle real CSV with a dedicated parser or a spreadsheet program.

Q4. A value that breaks the rule, like "1234-5678", reaches your phone-cleanup function. What is the best way to handle it?

⭕ Correct

❌ Not quite — see the explanation

Answer and explanation
Answer ③ Return a marker like null and collect it separately for a person to check

Guessing at unknown values quietly mixes wrong data in. Mark the values you could not process and have a person check them.

Q5. Write two ways to verify the results of an automation.

Answer and explanation
Answer A count check, adding the processed and on-hold counts to see whether they equal the original count, and a sample check, picking a few lines and comparing them with the original by hand (or double-checking a total another way)

Doing count, sample and total checks together catches most mistakes, such as picking the wrong column or losing lines.

🧪 Code lab

Build small automation functions using fictional records. The tests include edge cases such as empty data and malformed values.

Your code runs only inside an isolated sandbox in this browser and is never sent to a server. It has no network access and is stopped after 2 seconds. Edited code is saved only in this browser. Ctrl+Enter (⌘+Enter) runs it; Tab inserts two spaces (press Esc, then Tab, to move on).

JavaScript is off, so the code can't run here, but you can still read each task, its starter code, the automatic checks and a sample solution.

1Totaling amounts

Complete the function totalAmount(text). text is a string whose first line is the header name,amount, followed from the second line by name,amount records. Return the sum of all amounts as a number. Return 0 if there are no records, and skip blank lines.

Automatic checks
  • totalAmount("name,amount\nAlex,3000\nSam,4500")expected 7500
  • totalAmount("name,amount\nJay,1200\n\nAlex,800\n")expected 2000
  • totalAmount("name,amount")expected 0
  • totalAmount("name,amount\nSam,0\nJay,250")expected 250
💡 Hint

c[1] is a string. Convert it with Number(c[1]) before adding, and if line.trim() === "", move on with continue.

Show a sample solution
function totalAmount(text) {
  const lines = text.split("\n").slice(1);
  let total = 0;
  for (const line of lines) {
    if (line.trim() === "") continue;
    const c = line.split(",");
    total += Number(c[1]);
  }
  return total;
}

2Cleaning up a name list

Complete the function cleanNames(list). It takes an array of strings; remove the leading and trailing spaces of each name, shrink runs of spaces to a single space, then drop empty names and remove duplicates, and return the resulting array. Keep the order in which names first appear.

Automatic checks
  • cleanNames([" Alex ","Sam","Alex"])expected ["Alex","Sam"]
  • cleanNames(["Ann Lee","Ann Lee ",""])expected ["Ann Lee"]
  • cleanNames([])expected []
  • cleanNames([" ","","One"])expected ["One"]
  • cleanNames(["Sam","Alex","Sam","Alex"])expected ["Sam","Alex"]
💡 Hint

Shrink spaces with replace(/\s+/g, " "), drop empty strings with filter, then remove duplicates with [...new Set(array)].

Show a sample solution
function cleanNames(list) {
  const cleaned = list
    .map((s) => s.trim().replace(/\s+/g, " "))
    .filter((s) => s !== "");
  return [...new Set(cleaned)];
}

3Unifying phone number format

Complete the function formatPhone(s). If keeping only the digits of the string leaves 11 digits starting with 01, return it in the shape 010-1234-5678 (3-4-4); otherwise return null.

Automatic checks
  • formatPhone("01012345678")expected "010-1234-5678"
  • formatPhone("010 9876 5432")expected "010-9876-5432"
  • formatPhone("(010)1111.2222")expected "010-1111-2222"
  • formatPhone("1234-5678")expected null
  • formatPhone("")expected null
  • formatPhone("02-123-45678")expected null
💡 Hint

s.replace(/\D/g, "") keeps only the digits. If d.length !== 11 || !d.startsWith("01"), return null.

Show a sample solution
function formatPhone(s) {
  const d = s.replace(/\D/g, "");
  if (d.length !== 11 || !d.startsWith("01")) {
    return null;
  }
  return d.slice(0, 3) + "-" + d.slice(3, 7) +
    "-" + d.slice(7);
}

4Per-group sums

Complete the function sumByGroup(text). text is a multi-line string whose first line is the header dept,amount. Return an object whose keys are department names and whose values are the sum of that department's amounts. Return an empty object {} if there are no records, and skip blank lines.

Automatic checks
  • sumByGroup("dept,amount\nSales,100\nDev,200\nSales,50")expected {"Dev":200,"Sales":150}
  • sumByGroup("dept,amount")expected {}
  • sumByGroup("dept,amount\nAdmin,0\n\nAdmin,30\n")expected {"Admin":30}
  • sumByGroup("dept,amount\nDev,10\nDev,20\nDev,30")expected {"Dev":60}
💡 Hint

Right now, when the same department appears again, the code overwrites the earlier value. Keep adding with (sums[c[0]] || 0) + Number(c[1]).

Show a sample solution
function sumByGroup(text) {
  const sums = {};
  const lines = text.split("\n").slice(1);
  for (const line of lines) {
    if (line.trim() === "") continue;
    const c = line.split(",");
    sums[c[0]] = (sums[c[0]] || 0) + Number(c[1]);
  }
  return sums;
}

🤖 Try asking AI like this

Copy a prompt and replace the [ ] parts with your own situation. Don't take the answer on trust — check it against this lesson.

When you want to turn a repetitive task into code

Every week I do [task description] by hand. The input looks like the fake example below, and I'd like the output to be [desired result shape]. Write it as a JavaScript function, and explain in comments how it handles fields to convert to numbers, blank lines and malformed lines. Don't throw away malformed lines; collect them separately.
[3–5 lines of fake example data]

When you want your automation code reviewed

Below is my JavaScript code that cleans up CSV-like text. Point out any place that modifies the original, any place where strings are not converted to numbers, and what happens with commas inside fields, blank lines and `\r` at line ends. Then give me 5 test inputs to check it.
[my code]

When you want to settle on cleanup rules

The [phone number/date/name] field has been entered in different shapes by different people. Look at the fake examples below, suggest a rule to unify them, and list the cases that do not fit the rule and need a person to check.
[fake examples]

🧰 Related tools

Tools for checking and tidying the JSON, regular expressions and text from this lesson. Don't paste real personal data or passwords.

References
  • MDN Web Docs — JavaScript Guide and the String, Array, Set and Object.entries reference pages
  • RFC 4180 — a general description of the CSV format (rules for commas, double quotes and line breaks)

Reached every goal above? Mark the lesson complete.

💻 Coding Basics

  1. 1What Is a Program? — Breaking Work into Sequence, Choice, and Repetition
  2. 2Values, Variables, and Types — Putting Name Tags on Values
  3. 3Conditionals — Taking Different Paths Depending on the Situation
  4. 4Loops — Doing the Same Thing Many Times, Exactly
  5. 5Functions — Splitting Work into Small Named Machines
  6. 6Arrays and Objects — Storing and Handling Data
  7. 7Strings and Text — Cutting, Finding and Replacing Characters
  8. 8Debugging and Reading Errors — Turning Red Text into Clues
  9. 9Simple Automation — Spreadsheet Math and Text Cleanup in Code
  10. 10Reading and Verifying AI-Written Code — Tests, Security, Licenses, Privacy
📚 Worth reading
📊Using AI for Spreadsheets, and Checking the Formulas→ 💻AI Coding Assistants: Security and Licence Risks→ 💬Practising Conversation in a Foreign Language with AI→ ⚙️Finding Work Tasks Worth Automating with AI→
← Foundations for the AI Era