Filter rows with each condition stating its rule: a cell that is not a number does not match a comparison, and an empty cell is not a zero
Initializing in your browser…
Keep and reorder chosen columns, with the list built from the widest row so a field beyond the header is not dropped
Find and replace with both halves stated: what the pattern matches, and whether $1 and $& in the replacement are patterns or text
View, sort and edit a CSV, with an undo stack that goes back exactly one step and a parse report that tells a broken quote from a ragged row
A price column holding a currency amount, a grouped thousand, an empty cell and a hex-looking product code, filtered on "is greater than 1000". Four of those five rows are decided by what the tool thinks a number is.
products.csv, filtered on price is greater than 1000
id,price 1,"$1,299.99" 2,999 3, 4,0x1F 5,"1,500"
Rows kept
1,$1,299.99 5,1,500 The rule this condition enforces: "The cell reads as a number and is above the value. A cell that is not a number does not match, and an empty cell is not a zero."
Rows 1 and 5 are the two prices above a thousand. A filter built on Number() keeps neither of them, because Number("$1,299.99") and Number("1,500") are both NaN, and it keeps row 4 instead, because Number("0x1F") is 31. Row 3 is the one that matters most: an empty cell is not a zero, so it does not quietly satisfy a comparison against a positive number the way Number("") does.
Keep the rows that match your conditions, with each condition’s rule written out on the page. A filter is only as good as what it means by "greater than 10" and "is a date", so this one says: a cell that is not a number does not match a numeric comparison, an empty cell is not a zero, and 29 February in a common year is not a date.
A filter is an acceptor, so the question that matters is which rows it keeps that it should not. Every operator here goes to a decider rather than a coercion.
**Numbers.** A cell is read as a number under a stated decimal grammar: sign, digits, one decimal separator, an optional exponent, and around it the decorations a spreadsheet adds, so 1,234, $50, 50% and (500) are all numbers. `0x1F`, `0b101`, `Infinity`, `NaN` and `1_000` are not, and neither is an empty cell or one holding a space. That last one matters more than it looks: `Number("")` is 0, which is how an empty cell comes to pass "less than 10".
**Dates.** A date is a real calendar date. A bare number is not one, 29 February in a common year is not one, and 31 April is not one. A day-first date like 15/01/2024 IS one, which the JavaScript Date constructor refuses outright.
**Text.** Comparison is exact by default: case, surrounding spaces and the spelling of an accented letter all count. Turn on the matching options and each is an independent switch, with case folded in the Unicode sense so the German sharp s matches ss.
**A condition that cannot be evaluated is not the same as a condition nothing matches.** A mistyped regular expression, a bound that is not a number, a missing second bound: each is reported with the reason and takes no part in the filter, rather than quietly hiding every row. And a condition you switch OFF takes no part at all, which is not the same as one that matches everything.
Conditions go in groups, each group joining its own with AND or OR, and the groups joined with AND or OR in turn. The whole arrangement can be saved, exported and imported.
Combine "is empty" on one column with a numeric threshold on another to find the records that are both incomplete and material.
Group conditions so that region is one of a list AND either the value is above a threshold OR the date is recent.
"is a number" and "is a date" tell you how many cells really are, under a definition you can read, rather than under whatever the browser guesses.
A column holding $1,299.99 and 999 filters correctly on "is greater than 1000". A comparison built on Number() reads the first as NaN and drops it.
"is empty" matches a cell holding nothing and a cell holding only spaces, and does not match a zero.
Filtering on the pattern [ reports "that is not a valid regular expression" and leaves every row in place, instead of showing an empty table with no explanation.
It does not here. That is what happens when a filter uses Number(), because Number("") is 0. A cell that is not a number does not match a numeric comparison at all.
Yes. $1,299.99 is the number 1299.99, 50% is 0.5, and (500) is -500. Those are the numbers people have in spreadsheets.
Because it is a string in a CSV file, not a hexadecimal literal. Number() reads it as 31, which is a JavaScript convention rather than a data one.
That was a bug and it is fixed. A disabled condition now takes no part at all; previously it evaluated to true, which inside an OR group made every row match.
The page tells you, with the error from the pattern, and that condition takes no part in the filter. It does not silently match nothing.
Rows and columns are parsed and transformed in memory in your browser. No record ever reaches a server.