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.
| Criterion | Question to ask yourself | Signs that point toward automating |
|---|---|---|
| Repetition | How often do I do this? | It repeats daily, weekly or monthly |
| Rules | Can I write the processing rules in words? | Even the exceptions fit in a few lines |
| Volume | How many records at a time? | Dozens or more, too many to check by eye |
| Cost of mistakes | How bad is it if it is wrong? | Done by hand, items get missed or mistyped often |
| Change | Does the input format change often? | Column order and format stay almost the same |
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.
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]);[ 'date', 'item', 'qty', 'price' ]
4
{ date: '2026-03-01', item: 'pencil', qty: 10, price: 500 }+ 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"));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.
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);Total sales 14700
Average qty 5.5
{ pencil: 7500, notebook: 6000, eraser: 1200 }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]);{ Sales: 50000, Dev: 41000, Admin: 9000 }
Top spender: Sales- Step 1: Split the text into lines and skip the header.
- 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). - Step 3: Add each amount to an empty object, using the department name as the key.
- Step 4: Turn the object into an array of
[department, total]pairs withObject.entries, then loop through it and remember the largest value. - Check: Sales should be 32,000 + 18,000 = 50,000 won; confirm the code gives the same.
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.
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);[ '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)]);[ '[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.
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));
}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
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));
}"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.
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);5 [ '2026-03-03', '"pencil', ' blue"', '2', '500' ]
\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);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.
📌 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 withsplit(","), and convert numeric fields withNumber - 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
nullor 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
🧪 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.
totalAmount("name,amount\nAlex,3000\nSam,4500")expected7500totalAmount("name,amount\nJay,1200\n\nAlex,800\n")expected2000totalAmount("name,amount")expected0totalAmount("name,amount\nSam,0\nJay,250")expected250
💡 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.
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.
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")expectednullformatPhone("")expectednullformatPhone("02-123-45678")expectednull
💡 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.
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.
- Regex TesterCheck in advance what cleanup regular expressions like
\s+and\Dmatch in a sample sentence. - Text Diff CheckerPut the text before and after cleanup side by side and look only at the changed lines, to verify the code did not change anything it shouldn't.
- JSON FormatterExport the array of objects your code built with
JSON.stringifyand expand it neatly to inspect the table structure. - Character CounterCompare character and line counts before and after cleanup to roughly check that nothing was lost or added.
- 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.
Storage is unavailable in this browser, so this lasts only for this page.💻 Coding Basics
- 1What Is a Program? — Breaking Work into Sequence, Choice, and Repetition
- 2Values, Variables, and Types — Putting Name Tags on Values
- 3Conditionals — Taking Different Paths Depending on the Situation
- 4Loops — Doing the Same Thing Many Times, Exactly
- 5Functions — Splitting Work into Small Named Machines
- 6Arrays and Objects — Storing and Handling Data
- 7Strings and Text — Cutting, Finding and Replacing Characters
- 8Debugging and Reading Errors — Turning Red Text into Clues
- 9Simple Automation — Spreadsheet Math and Text Cleanup in Code
- 10Reading and Verifying AI-Written Code — Tests, Security, Licenses, Privacy