Filtering
cols includes a built-in expression language for filtering lines. Parse an expression, then evaluate it against each line’s data.
Basic usage
#![allow(unused)]
fn main() {
use cols::Filter;
let filter = Filter::parse(r#"SIZE > 1G && TYPE == "disk""#).unwrap();
let matches = filter.evaluate(|column_name| match column_name {
"SIZE" => Some("4294967296".into()), // 4G in bytes
"TYPE" => Some("disk".into()),
_ => None,
}).unwrap();
assert!(matches);
}
The evaluate closure maps column names to their string values for the current row. Return None for unknown columns (treated as empty string).
Operators
Comparison
| Operator | Word form | Meaning |
|---|---|---|
== | EQ | Equal |
!= | NE | Not equal |
< | LT | Less than |
<= | LE | Less or equal |
> | GT | Greater than |
>= | GE | Greater or equal |
Regex
Regex operators require the regex feature:
cols = { version = "0.2", features = ["regex"] }
| Operator | Meaning |
|---|---|
=~ | Matches regex |
!~ | Does not match regex |
Filter::parse(r#"NAME =~ "sd[a-z]""#).unwrap();
Boolean
| Operator | Word form | Meaning |
|---|---|---|
&& | AND | Logical and |
|| | OR | Logical or |
! | NOT | Logical not |
Parentheses control precedence: (A || B) && C.
Literals
- Integers:
42,0 - Integer suffixes:
1K(1024),2M,1G,4T— optionally withiBsuffix (1KiB) - Floats:
3.14,0.5 - Strings:
"hello",'world' - Booleans:
true,false
Column references
Bare identifiers are column name references (called “holders”):
SIZE > 1G
Here SIZE is resolved via the closure at evaluation time. A bare holder is truthy if the column has a non-empty value.
Extracting column names
#![allow(unused)]
fn main() {
let filter = Filter::parse(r#"SIZE > 1G && TYPE == "disk""#).unwrap();
let columns = filter.holders(); // ["SIZE", "TYPE"]
}
Useful for knowing which columns a filter depends on.
Filtering at print time
The simplest way to filter is to set a filter expression on the table. Non-matching lines are skipped during printing. Column names in the expression are resolved automatically by matching against column headers.
let mut t = fruit_table();
t.filter_set(r#"COLOR == "red""#).unwrap();
FRUIT PRICE COLOR
apple 1.20 red
cherry 3.00 red
The filter works with all output modes. Here’s the same filter as CSV:
FRUIT,PRICE,COLOR
apple,1.20,red
cherry,3.00,red
Call table.filter_clear() to remove the filter and show all lines again.
Custom resolver
By default, column names in the filter expression are matched against column headers. If you need custom resolution (e.g. computed values or renamed columns), set a resolver:
table.filter_resolver_set(|line, col_name| match col_name {
"BYTES" => line.data_get(1).map(String::from),
_ => None,
});
Manual filtering
You can also filter manually by iterating lines and building a new table. This gives full control over the filtering logic.
/// Helper: build a device table for filter demos.
fn device_table() -> Table {
let mut t = Table::new();
t.new_column("NAME");
t.new_column("TYPE");
t.new_column("SIZE");
let devices = [
("sda", "disk", "500107862016"), // 500G
("sda1", "part", "268435456"), // 256M
("sda2", "part", "499839426560"), // ~465G
("sdb", "disk", "2000398934016"), // 2T
("sdb1", "part", "1073741824"), // 1G
("sdb2", "part", "1999325192192"), // ~1.8T
("nvme0n1", "disk", "512110190592"), // 512G
("sr0", "rom", "0"),
("loop0", "loop", "109051904"), // 104M
];
for (name, typ, size) in devices {
let row = t.new_line(None);
t.line_mut(row)
.data_set(0, name)
.data_set(1, typ)
.data_set(2, size);
}
t
}
Filter by type
fn main() {
let source = device_table();
let filtered = filter_table(&source, r#"TYPE == "disk""#);
print_table(&filtered, &mut std::io::stdout().lock()).unwrap();
}
NAME TYPE SIZE
sda disk 500107862016
sdb disk 2000398934016
nvme0n1 disk 512110190592
Filter by size (with integer suffix)
The expression SIZE > 1G uses the suffix G (1024^3). The filter
automatically parses the cell’s string value as an integer for comparison.
fn main() {
let source = device_table();
let filtered = filter_table(&source, "SIZE > 1G");
print_table(&filtered, &mut std::io::stdout().lock()).unwrap();
}
NAME TYPE SIZE
sda disk 500107862016
sda2 part 499839426560
sdb disk 2000398934016
sdb2 part 1999325192192
nvme0n1 disk 512110190592
Combined filter
fn main() {
let source = device_table();
let filtered = filter_table(&source, r#"TYPE == "disk" && SIZE > 1G"#);
print_table(&filtered, &mut std::io::stdout().lock()).unwrap();
}
NAME TYPE SIZE
sda disk 500107862016
sdb disk 2000398934016
nvme0n1 disk 512110190592