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 } } #}