2017-06-29 6 views
2

&[u8]のバイトを一致させる必要があり、コードを簡素化したいと考えています。 は今、それは次のようになります。任意の位置で複数のバイトを一致させるにはどうすればよいですか?

fn f(s: &[u8]) { 
    if Some(&b'A') == s.get(5) && Some(&b'X') == s.get(16) && 
     (Some(&b'B') == s.get(17) || Some(&b'C') == s.get(18)) { 
    } else if Some(&b'1') == s.get(4) && Some(&b'2') == s.get(7) && Some(&b'D') == s.get(10) { 
    } 
} 

私は約nomを知っているが、私は試合後にデータを抽出するために、その後nom使用しているものの、それは、この特定のケースを簡単にしません。

だから、コードを単純化するために、私の最初の試みは、これらのマクロを書くことです:

macro_rules! m { 
    ($ch:expr, $pos:expr) => {{ 
     Some(&$ch) == line.get($pos) 
    }}; 
    ($ch1:expr, $ch2:expr, $pos:expr) => {{ 
     Some(&$ch1) == line.get($pos) || Some(&$ch2) == line.get($pos) 
    }} 
} 

これは、コードサイズを削減し、ミスを作る可能性を減少させ、 が、私はもっと欲しい:

macro_rules! match_several { 
    ($($ch:expr, $pos:expr),*, $last_ch:expr, $last_pos:expr) => {{ 
     (Some(&$ch) == line.get($pos) &&)* Some(&$last_ch) == line.get($last_pos) 
    }} 
} 

コンパイラはこのエラーを返します:

error: local ambiguity: multiple parsing options: built-in NTs expr ('last_ch') or expr ('ch'). 
    --> lib.rs:45:32 
    | 
45 |  if match_several!(b'P', 4, b' ', 5, b'A', 12) { 
    |  ------------------------^^^^-------------- in this macro invocation 

テストコード:

let line: &'static [u8] = b"0123P 6789ABA"; 
println!("match result {:?}", match_several!(b'P', 4, b' ', 5, b'A', 12)); 
+0

'match_several! 'のテストに使用したコードを含めることはできますか? –

+0

@ E_net4完了しました。 "テストコード" – user1244932

答えて

4

変更マクロへ:私はセパレータとして&&を使用してい

macro_rules! match_several { 
    ($($ch:expr, $pos:expr),*) => {{ 
     $(Some(&$ch) == line.get($pos))&&* 
    }} 
} 

注意、と私は$last_ch$last_posを処分しました。これは、+または*以外の任意のトークンを区切り記号として使用でき、&&が単一のトークンであるために機能します。

+0

*を含めることができます。+や*以外のトークンを区切り記号*として使用できます。何。心が吹かれました。 – Shepmaster

3

この場合の反復パターンは、やや便利な機能として抽象化することができます。

#[inline] 
fn all_match(s: &[u8], pattern: &[(u8, usize)]) -> bool { 
    pattern.into_iter().all(|&(b, p)| s.get(p) == Some(&b)) 
} 

#[inline] 
fn any_match(s: &[u8], pattern: &[(u8, usize)]) -> bool { 
    pattern.into_iter().any(|&(b, p)| s.get(p) == Some(&b)) 
} 

fn f(s: &[u8]) { 
    let and_pattern = [(b'A', 5), (b'X', 16)]; 
    let or_pattern = [(b'B', 17), (b'C', 18)]; 
    if all_match(s, &and_pattern) 
     && any_match(s, &or_pattern) { 
    } else if all_match(s, &[(b'1', 4), (b'2', 7), (b'D', 10)]) { 
    } 
} 
関連する問題