Rail Fence Cipher

1. Readme

篱笆密码法(栅栏密码)

实现篱笆密码法的编/解码.

篱笆密码法是一种置换式密码,它从编码的方式得到它的名字。它早被古希腊人所使用。

在 栅栏 密码中,信息向下写在虚构的篱笆的连续”rail”上,然后当我们到达底部时,又向上移动(像锯齿形)。最后,消息以行读取.

例如,使用三个”Rails(栅栏)”,和加密”WE ARE DISCOVERED FLEE AT ONCE”信息,密文写道:

W . . . E . . . C . . . R . . . L . . . T . . . E
. E . R . D . S . O . E . E . F . E . A . O . C .
. . A . . . I . . . V . . . D . . . E . . . N . .

然后读出:

WECRLTEERDSOEEFEAOCAIVDEN

要解密一条消息,你要采用锯齿形读法,而密文则是一行一行看。

? . . . ? . . . ? . . . ? . . . ? . . . ? . . . ?
. ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? .
. . ? . . . ? . . . ? . . . ? . . . ? . . . ? . .

第一行有七个点,可以用”WECRRLTE”填充.

W . . . E . . . C . . . R . . . L . . . T . . . E
. ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? .
. . ? . . . ? . . . ? . . . ? . . . ? . . . ? . .

现在第二行为”ERDSOEEFEAOC”.

W . . . E . . . C . . . R . . . L . . . T . . . E
. E . R . D . S . O . E . E . F . E . A . O . C .
. . ? . . . ? . . . ? . . . ? . . . ? . . . ? . .

最后一排”AIVDEN”.

W(1) . . . E . . . C . . . R . . . L . . . T . . . E
. E(2) . R . D . S . O . E . E . F . E . A . O . C .
. . A(3) . . . I . . . V . . . D . . . E . . . N . .

1,2,3只是为了方便理解,不存在任何地方

如果你现在锯齿形阅读,你可以阅读原始消息.

资源

维基百科https://en.wikipedia.org/wiki/Transposition_cipher#Rail_Fence_cipher

百度百科 https://baike.baidu.com/item/%E6%A0%85%E6%A0%8F%E5%AF%86%E7%A0%81

2. 开始你的表演

pub struct RailFence;

impl RailFence {
   pub fn new(rails: u32) -> RailFence {
       unimplemented!("Construct a new fence with {} rails", rails)
   }

   pub fn encode(&self, text: &str) -> String {
       unimplemented!("Encode this text: {}", text)
   }

   pub fn decode(&self, cipher: &str) -> String {
       unimplemented!("Decode this ciphertext: {}", cipher)
   }
}

3. 测试代码查看


# #![allow(unused_variables)]
#fn main() {
/// Tests for rail-fence-cipher
///
/// Generated by [script][script] using [canonical data][canonical-data]
///
/// [script]: https://github.com/exercism/rust/blob/master/bin/init_exercise.py
/// [canonical-data]: https://raw.githubusercontent.com/exercism/problem-specifications/master/exercises/rail-fence-cipher/canonical_data.json
///
/// The tests do not expect any normalization or cleaning.
/// That trade is tested in enough other exercises.

/// Process a single test case for the property `encode`
///
/// All cases for the `encode` property are implemented
/// in terms of this function.
fn process_encode_case(input: &str, rails: u32, expected: &str) {
   let rail_fence = RailFence::new(rails);
   assert_eq!(rail_fence.encode(input), expected);
}

/// Process a single test case for the property `decode`
///
/// All cases for the `decode` property are implemented
/// in terms of this function.
fn process_decode_case(input: &str, rails: u32, expected: &str) {
   let rail_fence = RailFence::new(rails);
   assert_eq!(rail_fence.decode(input), expected);
}

// encode

#[test]
/// encode with two rails
fn test_encode_with_two_rails() {
   process_encode_case("XOXOXOXOXOXOXOXOXO", 2, "XXXXXXXXXOOOOOOOOO");
}

#[test]
//#[ignore]
/// encode with three rails
fn test_encode_with_three_rails() {
   process_encode_case("WEAREDISCOVEREDFLEEATONCE", 3, "WECRLTEERDSOEEFEAOCAIVDEN");
}

#[test]
//#[ignore]
/// encode with ending in the middle
fn test_encode_with_ending_in_the_middle() {
   process_encode_case("EXERCISES", 4, "ESXIEECSR");
}

// decode

#[test]
//#[ignore]
/// decode with three rails
fn test_decode_with_three_rails() {
   process_decode_case("TEITELHDVLSNHDTISEIIEA", 3, "THEDEVILISINTHEDETAILS");
}

#[test]
//#[ignore]
/// decode with five rails
fn test_decode_with_five_rails() {
   process_decode_case("EIEXMSMESAORIWSCE", 5, "EXERCISMISAWESOME");
}

#[test]
//#[ignore]
/// decode with six rails
fn test_decode_with_six_rails() {
   process_decode_case(
       "133714114238148966225439541018335470986172518171757571896261",
       6,
       "112358132134558914423337761098715972584418167651094617711286",
   );
}

#[test]
//#[ignore]
/// encode wide characters
///
/// normally unicode is not part of exercism exercises, but in an exercise
/// specifically oriented around shuffling characters, it seems worth ensuring
/// that wide characters are handled properly
///
/// this text is possibly one of the most famous haiku of all time, by
/// Matsuo Bashō (松尾芭蕉)
fn test_encode_wide_characters() {
   process_encode_case(
       "古池 蛙飛び込む 水の音",
       3,
       "古飛 池蛙びむ水音 込の",
   );
}

#}

4. 答案


# #![allow(unused_variables)]
#fn main() {
pub struct RailFence(u32);

fn uncons(s: &str) -> (&str, &str) {
   s.split_at(s.chars().next().map_or(0, |c| c.len_utf8()))
}

impl RailFence {
   pub fn new(rails: u32) -> RailFence {
       RailFence(rails)
   }

   fn next(&self, down: &mut bool, rail: &mut usize) {
       if *down {
           if *rail + 1 < self.0 as usize {
               *rail += 1;
           } else {
               *down = false;
               *rail -= 1;
           }
       } else {
           if *rail > 0 {
               *rail -= 1;
           } else {
               *down = true;
               *rail += 1;
           }
       }
   }

   pub fn encode(&self, text: &str) -> String {
       let mut rails =
           vec![String::with_capacity(1 + (text.len() / self.0 as usize)); self.0 as usize];
       let mut down = true;
       let mut rail = 0;

       for ch in text.chars() {
           rails[rail].push(ch);
           self.next(&mut down, &mut rail);
       }

       rails.join("")
   }

   pub fn decode(&self, cipher: &str) -> String {
       let mut rail_caps = vec![0; self.0 as usize];
       let mut down = true;
       let mut rail = 0;

       for _ in cipher.chars() {
           rail_caps[rail] += 1;
           self.next(&mut down, &mut rail);
       }

       // this vector owns the text of each rail
       let mut rails_own = Vec::with_capacity(self.0 as usize);
       let mut skip = 0;

       for &cap in rail_caps.iter() {
           rails_own.push(
               cipher
                   .chars()
                   .skip(skip)
                   .enumerate()
                   .take_while(|&(i, _)| i < cap)
                   .map(|(_, c)| c)
                   .collect::<String>(),
           );
           skip += cap;
       }

       // this vector holds string slices viewing into rails_own
       let mut rails: Vec<&str> = rails_own.iter().map(|r| r.as_ref()).collect();

       let mut out = String::with_capacity(cipher.len());
       down = true;
       rail = 0;

       while rails.iter().any(|r: &&str| r.len() > 0) {
           let (head, t_rail) = uncons(rails[rail]);
           rails[rail] = t_rail;
           self.next(&mut down, &mut rail);
           out.push_str(head);
       }

       out
   }
}

#}



填充/相关