Skip to content

Instantly share code, notes, and snippets.

@natekford
Last active December 26, 2021 23:18
Show Gist options
  • Select an option

  • Save natekford/c06c0f4d314b2b0b8539ad562dce2b68 to your computer and use it in GitHub Desktop.

Select an option

Save natekford/c06c0f4d314b2b0b8539ad562dce2b68 to your computer and use it in GitHub Desktop.
Why is searching for an arbitrary number of strings so hard in Google Sheets?
using System.Text;
const string SHEET = "Notes";
const char COLUMN_START = 'A';
const char COLUMN_END = 'D';
const int ROW = 2;
var formula = new StringBuilder($"= QUERY(\n\t{SHEET}!{COLUMN_START}{ROW}:{COLUMN_END},\n\t\"select ");
formula.AppendJoin(", ", Enumerable.Range(COLUMN_START, COLUMN_END - COLUMN_START + 1).Select(x => (char)x));
formula.Append(" where 1=1\"\n");
for (var i = COLUMN_START; i <= COLUMN_END; ++i)
{
formula.Append($"\t&IFERROR(\" and lower({i}) matches '.*\"&JOIN(\n\t\t\".*' and lower({i}) matches '.*\",");
formula.Append($"\n\t\tSPLIT(REGEXREPLACE(lower({i}{ROW}), \",\\s*\", \",\"), \",\")\n\t)&\".*'\", \"\")\n");
}
formula.Append(')');
Console.WriteLine(formula.ToString());
// Google Sheets doesn't support lookarounds, so we can't do something like (?=.*cat)(?=.*dog)
// We have to either use an ugly as hell and unreadable formula using ARRAYFORMULA and MMULT
// or we have to use SQL to check some basic string contains
// REGEXREPLACE is used instead of TRIM because JOIN("sep", TRIM(SPLIT("a,b", ",")))
// just straight up ignores all split segments after the first one
// QUERY matches doesn't support (?i) so we have to convert everything to lower
// I love Google Sheets
/*
= QUERY(
Notes!A2:D,
"select A, B, C, D where 1=1"
&IFERROR(" and lower(A) matches '.*"&JOIN(
".*' and lower(A) matches '.*",
SPLIT(REGEXREPLACE(lower(A2), ",\s*", ","), ",")
)&".*'", "")
&IFERROR(" and lower(B) matches '.*"&JOIN(
".*' and lower(B) matches '.*",
SPLIT(REGEXREPLACE(lower(B2), ",\s*", ","), ",")
)&".*'", "")
&IFERROR(" and lower(C) matches '.*"&JOIN(
".*' and lower(C) matches '.*",
SPLIT(REGEXREPLACE(lower(C2), ",\s*", ","), ",")
)&".*'", "")
&IFERROR(" and lower(D) matches '.*"&JOIN(
".*' and lower(D) matches '.*",
SPLIT(REGEXREPLACE(lower(D2), ",\s*", ","), ",")
)&".*'", "")
)
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment