mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-29 12:07:46 +00:00
expr: prefix operators length/1, index/3 and substr/3
This commit is contained in:
parent
092e4d1ed4
commit
7b54410557
3 changed files with 56 additions and 3 deletions
|
@ -105,9 +105,9 @@ separates increasing precedence groups. EXPRESSION may be:
|
|||
STRING : REGEXP [NOT IMPLEMENTED] anchored pattern match of REGEXP in STRING
|
||||
|
||||
match STRING REGEXP [NOT IMPLEMENTED] same as STRING : REGEXP
|
||||
substr STRING POS LENGTH [NOT IMPLEMENTED] substring of STRING, POS counted from 1
|
||||
index STRING CHARS [NOT IMPLEMENTED] index in STRING where any CHARS is found, or 0
|
||||
length STRING [NOT IMPLEMENTED] length of STRING
|
||||
substr STRING POS LENGTH substring of STRING, POS counted from 1
|
||||
index STRING CHARS index in STRING where any CHARS is found, or 0
|
||||
length STRING length of STRING
|
||||
+ TOKEN interpret TOKEN as a string, even if it is a
|
||||
keyword like 'match' or an operator like '/'
|
||||
|
||||
|
|
|
@ -103,6 +103,9 @@ impl ASTNode {
|
|||
|a: &String, b: &String| Ok( bool_as_string(a >= b) ),
|
||||
&operand_values
|
||||
),
|
||||
"length" => prefix_operator_length( &operand_values ),
|
||||
"index" => prefix_operator_index( &operand_values ),
|
||||
"substr" => prefix_operator_substr( &operand_values ),
|
||||
|
||||
_ => Err(format!("operation not implemented: {}", op_type))
|
||||
}
|
||||
|
@ -328,6 +331,55 @@ fn infix_operator_two_ints_or_two_strings<FI, FS>( fi: FI, fs: FS, values: &Vec<
|
|||
}
|
||||
}
|
||||
|
||||
fn prefix_operator_length( values: &Vec<String> ) -> Result<String, String> {
|
||||
assert!( values.len() == 1 );
|
||||
Ok( values[0].len().to_string() )
|
||||
}
|
||||
|
||||
fn prefix_operator_index( values: &Vec<String> ) -> Result<String, String> {
|
||||
assert!( values.len() == 2 );
|
||||
let haystack = &values[0];
|
||||
let needles = &values[1];
|
||||
|
||||
let mut current_idx = 0;
|
||||
for ch_h in haystack.chars() {
|
||||
current_idx += 1;
|
||||
|
||||
for ch_n in needles.chars() {
|
||||
if ch_n == ch_h {
|
||||
return Ok( current_idx.to_string() )
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok( "0".to_string() )
|
||||
}
|
||||
|
||||
fn prefix_operator_substr( values: &Vec<String> ) -> Result<String, String> {
|
||||
assert!( values.len() == 3 );
|
||||
let subj = &values[0];
|
||||
let mut idx = match values[1].parse::<i64>() {
|
||||
Ok( i ) => i,
|
||||
Err( _ ) => return Err( "expected integer as POS arg to 'substr'".to_string() ),
|
||||
};
|
||||
let mut len = match values[2].parse::<i64>() {
|
||||
Ok( i ) => i,
|
||||
Err( _ ) => return Err( "expected integer as LENGTH arg to 'substr'".to_string() ),
|
||||
};
|
||||
|
||||
if idx <= 0 || len <= 0 { return Ok( "".to_string() ) }
|
||||
|
||||
let mut out_str = String::new();
|
||||
for ch in subj.chars() {
|
||||
idx -= 1;
|
||||
if idx <= 0 {
|
||||
if len <= 0 { break; }
|
||||
len -= 1;
|
||||
|
||||
out_str.push( ch );
|
||||
}
|
||||
}
|
||||
Ok( out_str )
|
||||
}
|
||||
|
||||
fn bool_as_int( b: bool ) -> i64 { if b { 1 } else { 0 } }
|
||||
fn bool_as_string( b: bool ) -> String { if b { "1".to_string() } else { "0".to_string() } }
|
||||
|
|
|
@ -110,6 +110,7 @@ pub fn strings_to_tokens( strings: &Vec<String> ) -> Result< Vec<(usize, Token)>
|
|||
"match" => Token::PrefixOp{ arity: 2, value: s.clone() },
|
||||
"substr" => Token::PrefixOp{ arity: 3, value: s.clone() },
|
||||
"index" => Token::PrefixOp{ arity: 2, value: s.clone() },
|
||||
"length" => Token::PrefixOp{ arity: 1, value: s.clone() },
|
||||
|
||||
_ => Token::new_value( &s ),
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue