Open greymd opened 4 years ago
just a idea. I want to keep compatibility with cut
.
1~3
=> same chunk
1-3
=> three individual chunks
My new idea is this.
1-5 .. Just select from 1 to 5 (default)
1~5 .. from 1 to 5 are explicitly merged
1:5 .. from 1 to 5 are explicitly separated
Keep -
expression to keep backword compatibility.
That means, -
behavior changes depending on the other consolidated options, which is current behavior.
With -c
, merged, with -f
separated.
On the other hand, ~
can explicitly merge chunks.
Such like..
$ echo AAA BBB CCC | teip -f 1~2
[AAA BBB] CCC
:
can explicitly separate chunks on the other hand.
$ echo 123456789 | teip -f 2:5
1[2][3][4][5]6789
Syntax parser can be implemented something like that. They are patch for v2.2.0.
diff --git a/src/list/ranges.rs b/src/list/ranges.rs
index 85b20fe..6f71bf5 100644
--- a/src/list/ranges.rs
+++ b/src/list/ranges.rs
@@ -1,10 +1,8 @@
/*
- * This file is part of the uutils coreutils package.
+ * This file is based on the uutils coreutils package.
*
- * (c) Rolf Morel <rolfmorel@gmail.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
+ * For the full copyright and license information about
+ * the original file, please view the LICENSE
*/
use std::str::FromStr;
@@ -13,6 +11,17 @@ use std::str::FromStr;
pub struct Range {
pub low: usize,
pub high: usize,
+ pub join: RangeJoin,
+}
+
+#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
+pub enum RangeJoin {
+ /// 1-5 .. Just select from 1 to 5 (default)
+ Normal,
+ /// 1~5 .. from 1 to 5 are explicitly merged
+ Merge,
+ /// 1:5 .. from 1 to 5 are explicitly split
+ Split,
}
impl FromStr for Range {
@@ -20,8 +29,20 @@ impl FromStr for Range {
fn from_str(s: &str) -> Result<Range, &'static str> {
use std::usize::MAX;
-
- let mut parts = s.splitn(2, '-');
+ let join: RangeJoin;
+
+ // check if s includes a ~ or a - and split on that
+ // if not, assume it's a single number
+ let mut parts = if s.contains('~') {
+ join = RangeJoin::Merge;
+ s.splitn(2, '~')
+ } else if s.contains(':') {
+ join = RangeJoin::Split;
+ s.splitn(2, ':')
+ } else {
+ join = RangeJoin::Normal;
+ s.splitn(2, '-')
+ };
let field = "fields and positions are numbered from 1";
let order = "high end of range less than low end";
@@ -31,7 +52,7 @@ impl FromStr for Range {
(Some(nm), None) => {
if let Ok(nm) = nm.parse::<usize>() {
if nm > 0 {
- Ok(Range { low: nm, high: nm })
+ Ok(Range { low: nm, high: nm, join: RangeJoin::Normal })
} else {
Err(field)
}
@@ -42,7 +63,7 @@ impl FromStr for Range {
(Some(n), Some(m)) if m.is_empty() => {
if let Ok(low) = n.parse::<usize>() {
if low > 0 {
- Ok(Range { low, high: MAX - 1 })
+ Ok(Range { low, high: MAX - 1, join })
} else {
Err(field)
}
@@ -53,7 +74,7 @@ impl FromStr for Range {
(Some(n), Some(m)) if n.is_empty() => {
if let Ok(high) = m.parse::<usize>() {
if high > 0 {
- Ok(Range { low: 1, high })
+ Ok(Range { low: 1, high, join })
} else {
Err(field)
}
@@ -64,7 +85,7 @@ impl FromStr for Range {
(Some(n), Some(m)) => match (n.parse::<usize>(), m.parse::<usize>()) {
(Ok(low), Ok(high)) => {
if low > 0 && low <= high {
- Ok(Range { low, high })
+ Ok(Range { low, high, join })
} else if low == 0 {
Err(field)
} else {
@@ -111,11 +132,14 @@ pub fn complement(ranges: &[Range]) -> Vec<Range> {
use std::usize;
let mut complements = Vec::with_capacity(ranges.len() + 1);
+ // Use the default join type to keep back compatibility
+ const DEF_JOIN: RangeJoin = RangeJoin::Normal;
if !ranges.is_empty() && ranges[0].low > 1 {
complements.push(Range {
low: 1,
high: ranges[0].low - 1,
+ join: DEF_JOIN,
});
}
@@ -127,6 +151,7 @@ pub fn complement(ranges: &[Range]) -> Vec<Range> {
complements.push(Range {
low: left.high + 1,
high: right.low - 1,
+ join: DEF_JOIN,
});
}
}
@@ -135,6 +160,7 @@ pub fn complement(ranges: &[Range]) -> Vec<Range> {
complements.push(Range {
low: last.high + 1,
high: usize::MAX - 1,
+ join: DEF_JOIN,
});
}
}
diff --git a/src/list/converter.rs b/src/list/converter.rs
index b2841c1..5e17b1a 100644
--- a/src/list/converter.rs
+++ b/src/list/converter.rs
@@ -11,10 +11,80 @@ pub fn to_ranges(list: &str, complement: bool) -> Result<Vec<Range>, String> {
#[cfg(test)]
mod test {
use super::*;
+ use ranges::RangeJoin::{Merge, Normal, Split};
#[test]
fn test_to_ranges() {
let range = to_ranges("2-5,1-8", false).unwrap();
assert_eq!(range[0].low, 1);
assert_eq!(range[0].high, 8);
}
+ #[test]
+ fn test_to_ranges_merge_unmerge() {
+ let range = to_ranges("1-3,4~6", false).unwrap();
+ assert_eq!(range[0].low, 1);
+ assert_eq!(range[0].high, 3);
+ assert_eq!(range[0].join, Normal);
+ assert_eq!(range[1].low, 4);
+ assert_eq!(range[1].high, 6);
+ assert_eq!(range[1].join, Merge);
+ }
+ #[test]
+ fn test_to_ranges_unsort() {
+ let range = to_ranges("4,1-3,5~7", false).unwrap();
+ println!("{:?}", range);
+ assert_eq!(range[0].low, 1);
+ assert_eq!(range[0].high, 3);
+ assert_eq!(range[0].join, Normal);
+ assert_eq!(range[1].low, 4);
+ assert_eq!(range[1].high, 4);
+ assert_eq!(range[1].join, Normal);
+ assert_eq!(range[2].low, 5);
+ assert_eq!(range[2].high, 7);
+ assert_eq!(range[2].join, Merge);
+ }
+ #[test]
+ fn test_to_ranges_split() {
+ let range = to_ranges("1,2,3,4", false).unwrap();
+ println!("{:?}", range);
+ for i in 0..4 {
+ assert_eq!(range[i].low, i + 1);
+ assert_eq!(range[i].high, i + 1);
+ assert_eq!(range[i].join, Normal);
+ }
+ }
+ #[test]
+ fn test_to_ranges_split_unsort() {
+ let range = to_ranges("5,3,4,1,2", false).unwrap();
+ println!("{:?}", range);
+ for i in 0..5 {
+ assert_eq!(range[i].low, i + 1);
+ assert_eq!(range[i].high, i + 1);
+ assert_eq!(range[i].join, Normal);
+ }
+ }
+ #[test]
+ fn test_to_ranges_overwrap() {
+ let range = to_ranges("1-3,2~5", false).unwrap();
+ println!("{:?}", range);
+ assert_eq!(range[0].low, 1);
+ assert_eq!(range[0].high, 5);
+ assert_eq!(range[0].join, Normal);
+ }
+ #[test]
+ fn test_to_ranges_three_different_range() {
+ let range = to_ranges("1-3,5:10,12,13~15", false).unwrap();
+ println!("{:?}", range);
+ assert_eq!(range[0].low, 1);
+ assert_eq!(range[0].high, 3);
+ assert_eq!(range[0].join, Normal);
+ assert_eq!(range[1].low, 5);
+ assert_eq!(range[1].high, 10);
+ assert_eq!(range[1].join, Split);
+ assert_eq!(range[2].low, 12);
+ assert_eq!(range[2].high, 12);
+ assert_eq!(range[2].join, Normal);
+ assert_eq!(range[3].low, 13);
+ assert_eq!(range[3].high, 15);
+ assert_eq!(range[3].join, Merge);
+ }
}
echo ABCDE | teip -c '1,3,$-1' => [A]B[C][D]E
$-1
supposed to be 4, because$
means the number of field.Instead of
-
,..
is used for specifying the range.1..3
=>1,2,3