diff --git a/src/class/SimpleDB.ts b/src/class/SimpleDB.ts index fec7c504..10aa8c14 100644 --- a/src/class/SimpleDB.ts +++ b/src/class/SimpleDB.ts @@ -1125,6 +1125,9 @@ export default class SimpleDB { * * // Replaces only if matching entire string. * await sdb.replaceStrings("tableA", "column1", {"kilograms": "kg", liters: "l" }, {entireString: true}) + * + * // Replaces using a regular expression. Any sequence of one or more digits would be replaced by a hyphen. + * await sdb.replaceStrings("tableA", "column1", {"\d+": "-" }, {regex: true}) * ``` * * @param table - The name of the table in which strings will be replaced. @@ -1132,7 +1135,7 @@ export default class SimpleDB { * @param strings - An object mapping old strings to new strings. * @param options - An optional object with configuration options: * @param options.entireString - A boolean indicating whether the entire string must match for replacement. Defaults to false. - * + * @param options.regex - A boolean indicating the use of regular expressions for a global replace. See the [RE2 docs](https://github.com/google/re2/wiki/Syntax) for the syntax. Defaults to false. * @category Updating data */ async replaceStrings( @@ -1141,9 +1144,16 @@ export default class SimpleDB { strings: { [key: string]: string }, options: { entireString?: boolean + regex?: boolean } = {} ) { options.entireString = options.entireString ?? false + options.regex = options.regex ?? false + if (options.entireString === true && options.regex === true) { + throw new Error( + "You can't have entireString to true and regex to true at the same time. Pick one." + ) + } await queryDB( this, replaceStringsQuery( diff --git a/src/methods/replaceStringsQuery.ts b/src/methods/replaceStringsQuery.ts index dc56ca5f..5e533bd6 100644 --- a/src/methods/replaceStringsQuery.ts +++ b/src/methods/replaceStringsQuery.ts @@ -3,7 +3,7 @@ export default function replaceStringsQuery( columns: string[], oldTexts: string[], newTexts: string[], - options: { entireString?: boolean } = {} + options: { entireString?: boolean; regex?: boolean } = {} ) { let query = "" @@ -18,6 +18,8 @@ export default function replaceStringsQuery( WHEN "${column}" = '${oldTexts[i]}' THEN '${newTexts[i]}' ELSE "${column}" END;\n` + } else if (options.regex) { + query += `UPDATE ${table} SET "${column}" = REGEXP_REPLACE("${column}", '${oldTexts[i]}', '${newTexts[i]}', 'g');\n` } else { query += `UPDATE ${table} SET "${column}" = REPLACE("${column}", '${oldTexts[i]}', '${newTexts[i]}');\n` } diff --git a/test/unit/methods/replaceStrings.test.ts b/test/unit/methods/replaceStrings.test.ts index 65cfd9e3..5f1542f6 100644 --- a/test/unit/methods/replaceStrings.test.ts +++ b/test/unit/methods/replaceStrings.test.ts @@ -2990,4 +2990,429 @@ describe("replaceString", () => { }, ]) }) + it("should use a regular expression", async () => { + await simpleNodeDB.loadData("employeesMultipleColumnsRegex", [ + "test/data/files/employees.csv", + ]) + + await simpleNodeDB.replaceStrings( + "employeesMultipleColumnsRegex", + "Hire date", + { "\\d+": "-" }, + { regex: true } + ) + + const data = await simpleNodeDB.getData("employeesMultipleColumnsRegex") + + assert.deepStrictEqual(data, [ + { + Name: "OConnell, Donald", + "Hire date": "--JUN--", + Job: "Clerk", + Salary: "2600", + "Department or unit": "50", + "End-of_year-BONUS?": "1,94%", + }, + { + Name: "OConnell, Donald", + "Hire date": "--JUN--", + Job: "Clerk", + Salary: "2600", + "Department or unit": "50", + "End-of_year-BONUS?": "1,94%", + }, + { + Name: "Grant, Douglas", + "Hire date": "--JAN--", + Job: "Clerk", + Salary: "NaN", + "Department or unit": "50", + "End-of_year-BONUS?": "23,39%", + }, + { + Name: null, + "Hire date": "--SEP--", + Job: "Assistant", + Salary: "4400", + "Department or unit": "10", + "End-of_year-BONUS?": "17,51%", + }, + { + Name: "Hartstein, Michael", + "Hire date": "--FEB--", + Job: "Manager", + Salary: "13000", + "Department or unit": "20", + "End-of_year-BONUS?": "2,71%", + }, + { + Name: "Fay, Pat", + "Hire date": "--AUG--", + Job: "Representative", + Salary: "6000", + "Department or unit": "20", + "End-of_year-BONUS?": "18,68%", + }, + { + Name: "Mavris, Susan", + "Hire date": "--JUN--", + Job: "Salesperson", + Salary: "6500", + "Department or unit": "40", + "End-of_year-BONUS?": "23,47%", + }, + { + Name: "NaN", + "Hire date": "--JUN--", + Job: "Salesperson", + Salary: "10000", + "Department or unit": "xyz", + "End-of_year-BONUS?": "17,63%", + }, + { + Name: "Higgins, Shelley", + "Hire date": "--JUN--", + Job: "Manager", + Salary: "12008", + "Department or unit": "110", + "End-of_year-BONUS?": "17,09%", + }, + { + Name: "null", + "Hire date": "--JUN--", + Job: "Accountant", + Salary: "8300", + "Department or unit": "110", + "End-of_year-BONUS?": "15,7%", + }, + { + Name: "King, Steven", + "Hire date": null, + Job: "President", + Salary: "24000", + "Department or unit": "90", + "End-of_year-BONUS?": "2,46%", + }, + { + Name: "Kochhar, Neena", + "Hire date": "--SEP--", + Job: "Vice-president", + Salary: "&6%", + "Department or unit": "90", + "End-of_year-BONUS?": "11,6%", + }, + { + Name: "De Haan, Lex", + "Hire date": "null", + Job: "Vice-president", + Salary: "17000", + "Department or unit": "90", + "End-of_year-BONUS?": "23,43%", + }, + { + Name: "Hunold, Alexander", + "Hire date": "--JAN--", + Job: "Programmer", + Salary: "9000", + "Department or unit": "60", + "End-of_year-BONUS?": "23,01%", + }, + { + Name: "Ernst, Bruce", + "Hire date": "--MAY--", + Job: "Programmer", + Salary: "6000", + "Department or unit": "60", + "End-of_year-BONUS?": "25,91%", + }, + { + Name: "Austin, David", + "Hire date": "NaN", + Job: "Programmer", + Salary: "4800", + "Department or unit": "null", + "End-of_year-BONUS?": "6,89%", + }, + { + Name: "Pataballa, Valli", + "Hire date": "abc", + Job: "Programmer", + Salary: null, + "Department or unit": "60", + "End-of_year-BONUS?": "1,62%", + }, + { + Name: "Lorentz, Diana", + "Hire date": "--ARB--", + Job: "Programmer", + Salary: "4200", + "Department or unit": "60", + "End-of_year-BONUS?": "13,17%", + }, + { + Name: "Greenberg, Nancy", + "Hire date": "--AUG--", + Job: "Manager", + Salary: "12008", + "Department or unit": "100", + "End-of_year-BONUS?": "74,69%", + }, + { + Name: "Faviet, Daniel", + "Hire date": "--AUG--", + Job: "Accountant", + Salary: "9000", + "Department or unit": "100", + "End-of_year-BONUS?": "2,92%", + }, + { + Name: "Chen, John", + "Hire date": "--SEP--", + Job: "Accountant", + Salary: "8200", + "Department or unit": "100", + "End-of_year-BONUS?": "9,31%", + }, + { + Name: "Sciarra, Ismael", + "Hire date": "--SEP--", + Job: "Accountant", + Salary: "7700", + "Department or unit": "100", + "End-of_year-BONUS?": "13,18%", + }, + { + Name: "Urman, Jose Manuel", + "Hire date": "--MAR--", + Job: "Accountant", + Salary: "7800", + "Department or unit": "100", + "End-of_year-BONUS?": "1,33%", + }, + { + Name: "Popp, Luis", + "Hire date": "--DEC--", + Job: "Accountant", + Salary: "6900", + "Department or unit": "100", + "End-of_year-BONUS?": "2,98%", + }, + { + Name: "Raphaely, Den", + "Hire date": "--DEC--", + Job: "Manager", + Salary: "11000", + "Department or unit": "30", + "End-of_year-BONUS?": "3,35%", + }, + { + Name: "Khoo, Alexander", + "Hire date": "--MAY--", + Job: "Clerk", + Salary: "3100", + "Department or unit": "30", + "End-of_year-BONUS?": "19,81%", + }, + { + Name: "Baida, Shelli", + "Hire date": "--DEC--", + Job: "Clerk", + Salary: "2900", + "Department or unit": "30", + "End-of_year-BONUS?": "11,06%", + }, + { + Name: "Tobias, Sigal", + "Hire date": "--JUL--", + Job: "NaN", + Salary: "2800", + "Department or unit": null, + "End-of_year-BONUS?": "undefined", + }, + { + Name: "Himuro, Guy", + "Hire date": "--NOV--", + Job: "Clerk", + Salary: "2600", + "Department or unit": "30", + "End-of_year-BONUS?": "25,98%", + }, + { + Name: "Colmenares, Karen", + "Hire date": "--AUG--", + Job: "Clerk", + Salary: "2500", + "Department or unit": "30", + "End-of_year-BONUS?": "15,8%", + }, + { + Name: "Weiss, Matthew", + "Hire date": "--JUL--", + Job: "Manager", + Salary: "8000", + "Department or unit": "50", + "End-of_year-BONUS?": "25,17%", + }, + { + Name: "Fripp, Adam", + "Hire date": "--APR--", + Job: "Manager", + Salary: "8200", + "Department or unit": "50", + "End-of_year-BONUS?": "21%", + }, + { + Name: "Kaufling, Payam", + "Hire date": "--MAY--", + Job: "Manager", + Salary: "7900", + "Department or unit": "undefined", + "End-of_year-BONUS?": "21,33%", + }, + { + Name: "Vollman, Shanta", + "Hire date": "--OCT--", + Job: "null", + Salary: "6500", + "Department or unit": "50", + "End-of_year-BONUS?": "3,45%", + }, + { + Name: "Mourgos, Kevin", + "Hire date": "undefined", + Job: "Manager", + Salary: "5800", + "Department or unit": "50", + "End-of_year-BONUS?": "19,07%", + }, + { + Name: "Nayer, Julia", + "Hire date": "--JUL--", + Job: "Clerk", + Salary: "3200", + "Department or unit": "50", + "End-of_year-BONUS?": "18,7%", + }, + { + Name: "Mikkilineni, Irene", + "Hire date": "--SEP--", + Job: "Clerk", + Salary: "2700", + "Department or unit": "50", + "End-of_year-BONUS?": "11,82%", + }, + { + Name: "Landry, James", + "Hire date": "--JAN--", + Job: "Clerk", + Salary: "2400", + "Department or unit": "50", + "End-of_year-BONUS?": "NaN", + }, + { + Name: "Markle, Steven", + "Hire date": "NaN", + Job: "Clerk", + Salary: "2200", + "Department or unit": "50", + "End-of_year-BONUS?": "11,26%", + }, + { + Name: "Bissot, Laura", + "Hire date": "--AUG--", + Job: "undefined", + Salary: "3300", + "Department or unit": "50", + "End-of_year-BONUS?": "4,53%", + }, + { + Name: "Atkinson, Mozhe", + "Hire date": "--OCT--", + Job: "Clerk", + Salary: "undefined", + "Department or unit": "50", + "End-of_year-BONUS?": "9,61%", + }, + { + Name: "Marlow, James", + "Hire date": "--FEB--", + Job: "Clerk", + Salary: "2500", + "Department or unit": "50", + "End-of_year-BONUS?": "15,74%", + }, + { + Name: "Olson, TJ", + "Hire date": "--APR--", + Job: "Clerk", + Salary: "2100", + "Department or unit": "null", + "End-of_year-BONUS?": "22,3%", + }, + { + Name: "undefined", + "Hire date": "--JUN--", + Job: "Clerk", + Salary: "3300", + "Department or unit": "50", + "End-of_year-BONUS?": "18,54%", + }, + { + Name: "Rogers, Michael", + "Hire date": "--AUG--", + Job: "Clerk", + Salary: "2900", + "Department or unit": "50", + "End-of_year-BONUS?": "null", + }, + { + Name: "Gee, Ki", + "Hire date": "--DEC--", + Job: "NaN", + Salary: "2400", + "Department or unit": "50", + "End-of_year-BONUS?": "12,64%", + }, + { + Name: "Philtanker, Hazel", + "Hire date": "--FEB--", + Job: "Clerk", + Salary: "2200", + "Department or unit": "NaN", + "End-of_year-BONUS?": "24,17%", + }, + { + Name: "Ladwig, Renske", + "Hire date": "--JUL--", + Job: null, + Salary: "3600", + "Department or unit": "50", + "End-of_year-BONUS?": "17,86%", + }, + { + Name: "Stiles, Stephen", + "Hire date": "--OCT--", + Job: "Clerk", + Salary: "3200", + "Department or unit": "50", + "End-of_year-BONUS?": null, + }, + { + Name: "Seo, John", + "Hire date": "--FEB--", + Job: "Clerk", + Salary: "2700", + "Department or unit": "50", + "End-of_year-BONUS?": "0,16%", + }, + { + Name: "Patel, Joshua", + "Hire date": "--APR--", + Job: "Clerk", + Salary: "2500", + "Department or unit": "50", + "End-of_year-BONUS?": "16,19%", + }, + ]) + }) })