栅栏密码(Rail Fence Cipher)是一种经典的置换密码,通过将明文按对角线方式写在多个"轨道"上,然后按行读取来实现加密。在 Exercism 的 "rail-fence-cipher" 练习中,我们需要实现栅栏密码的加密和解密功能。这不仅能帮助我们掌握字符串处理和算法设计技巧,还能深入学习Rust中的结构体设计、索引计算和字符操作。
什么是栅栏密码?
栅栏密码是一种置换密码,通过将明文按Z字形方式写在多个轨道(rails)上,然后按行读取来实现加密。解密过程则是相反的操作。
例如,使用3个轨道加密 "WEAREDISCOVEREDFLEEATONCE":
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"
让我们先看看练习提供的结构体和函数:
rust
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)
}
}
我们需要实现 RailFence 结构体,使其能够进行栅栏密码的加密和解密操作。
设计分析
1. 核心要求
- 结构体设计:设计 RailFence 结构体存储轨道数
- 加密实现:实现按Z字形方式排列字符的加密算法
- 解密实现:实现根据密文和轨道数还原明文的解密算法
- 字符处理:正确处理各种字符,包括宽字符
2. 技术要点
- Z字形模式:理解和实现字符在轨道间的Z字形分布
- 索引计算:计算字符在轨道中的位置
- 字符串操作:高效处理和重组字符串
- 算法设计:设计加密和解密算法
完整实现
1. 基础实现
rust
pub struct RailFence {
rails: u32,
}
impl RailFence {
pub fn new(rails: u32) -> RailFence {
RailFence { rails }
}
pub fn encode(&self, text: &str) -> String {
if self.rails <= 1 {
return text.to_string();
}
let n = self.rails as usize;
let mut rails: Vec<Vec<char>> = vec![Vec::new(); n];
let mut rail = 0;
let mut step = 1;
for c in text.chars() {
rails[rail].push(c);
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
rails.into_iter().flatten().collect()
}
pub fn decode(&self, cipher: &str) -> String {
if self.rails <= 1 {
return cipher.to_string();
}
let n = self.rails as usize;
let len = cipher.chars().count();
let mut rail_lengths = vec![0; n];
let mut rail = 0;
let mut step = 1;
// 计算每个轨道的字符数量
for _ in 0..len {
rail_lengths[rail] += 1;
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
// 将密文分割到各个轨道
let chars: Vec<char> = cipher.chars().collect();
let mut rails: Vec<Vec<char>> = vec![Vec::new(); n];
let mut start = 0;
for i in 0..n {
let end = start + rail_lengths[i];
rails[i] = chars[start..end].to_vec();
start = end;
}
// 重新构建明文
let mut result = String::new();
let mut rail_indices = vec![0; n];
rail = 0;
step = 1;
for _ in 0..len {
result.push(rails[rail][rail_indices[rail]]);
rail_indices[rail] += 1;
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
result
}
}
2. 优化实现
rust
pub struct RailFence {
rails: u32,
}
impl RailFence {
pub fn new(rails: u32) -> RailFence {
RailFence { rails }
}
pub fn encode(&self, text: &str) -> String {
if self.rails <= 1 {
return text.to_string();
}
let n = self.rails as usize;
let mut rails: Vec<String> = vec![String::new(); n];
let mut rail = 0;
let mut step = 1;
for c in text.chars() {
rails[rail].push(c);
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
rails.concat()
}
pub fn decode(&self, cipher: &str) -> String {
if self.rails <= 1 {
return cipher.to_string();
}
let n = self.rails as usize;
let len = cipher.chars().count();
// 计算每个轨道的字符数量
let mut rail_lengths = vec![0; n];
let mut rail = 0;
let mut step = 1;
for _ in 0..len {
rail_lengths[rail] += 1;
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
// 将密文分割到各个轨道
let chars: Vec<char> = cipher.chars().collect();
let mut rails: Vec<&[char]> = Vec::with_capacity(n);
let mut start = 0;
for &length in &rail_lengths {
let end = start + length;
rails.push(&chars[start..end]);
start = end;
}
// 重新构建明文
let mut result = String::with_capacity(len);
let mut rail_indices = vec![0; n];
rail = 0;
let mut step = 1;
for _ in 0..len {
result.push(rails[rail][rail_indices[rail]]);
rail_indices[rail] += 1;
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
result
}
}
3. 使用索引计算的实现
rust
pub struct RailFence {
rails: u32,
}
impl RailFence {
pub fn new(rails: u32) -> RailFence {
RailFence { rails }
}
pub fn encode(&self, text: &str) -> String {
if self.rails <= 1 {
return text.to_string();
}
let n = self.rails as usize;
let chars: Vec<char> = text.chars().collect();
let len = chars.len();
// 计算每个字符应该放在哪个轨道
let mut rail_indices: Vec<usize> = Vec::with_capacity(len);
let mut rail = 0;
let mut step = 1;
for _ in 0..len {
rail_indices.push(rail);
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
// 按轨道收集字符
let mut result = String::with_capacity(len);
for target_rail in 0..n {
for (i, &char_rail) in rail_indices.iter().enumerate() {
if char_rail == target_rail {
result.push(chars[i]);
}
}
}
result
}
pub fn decode(&self, cipher: &str) -> String {
if self.rails <= 1 {
return cipher.to_string();
}
let n = self.rails as usize;
let len = cipher.chars().count();
// 计算每个字符原来的位置
let mut rail_indices: Vec<usize> = Vec::with_capacity(len);
let mut rail = 0;
let mut step = 1;
for _ in 0..len {
rail_indices.push(rail);
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
// 构建位置映射
let mut positions: Vec<(usize, usize)> = rail_indices
.iter()
.enumerate()
.map(|(original, &rail)| (rail, original))
.collect();
// 按轨道和原始位置排序
positions.sort_by(|a, b| {
if a.0 == b.0 {
a.1.cmp(&b.1)
} else {
a.0.cmp(&b.0)
}
});
// 解密
let cipher_chars: Vec<char> = cipher.chars().collect();
let mut result_chars = vec![' '; len];
for (i, &(_, original_pos)) in positions.iter().enumerate() {
result_chars[original_pos] = cipher_chars[i];
}
result_chars.iter().collect()
}
}
测试用例分析
通过查看测试用例,我们可以更好地理解需求:
rust
#[test]
/// encode with two rails
fn test_encode_with_two_rails() {
process_encode_case("XOXOXOXOXOXOXOXOXO", 2, "XXXXXXXXXOOOOOOOOO");
}
使用2个轨道加密,将字符按X和O分组。
rust
#[test]
/// encode with three rails
fn test_encode_with_three_rails() {
process_encode_case("WEAREDISCOVEREDFLEEATONCE", 3, "WECRLTEERDSOEEFEAOCAIVDEN");
}
使用3个轨道加密经典的示例文本。
rust
#[test]
/// encode with ending in the middle
fn test_encode_with_ending_in_the_middle() {
process_encode_case("EXERCISES", 4, "ESXIEECSR");
}
使用4个轨道加密,结束位置在中间轨道。
rust
#[test]
/// decode with three rails
fn test_decode_with_three_rails() {
process_decode_case("TEITELHDVLSNHDTISEIIEA", 3, "THEDEVILISINTHEDETAILS");
}
使用3个轨道解密。
rust
#[test]
/// decode with five rails
fn test_decode_with_five_rails() {
process_decode_case("EIEXMSMESAORIWSCE", 5, "EXERCISMISAWESOME");
}
使用5个轨道解密。
rust
#[test]
/// decode with six rails
fn test_decode_with_six_rails() {
process_decode_case(
"133714114238148966225439541018335470986172518171757571896261",
6,
"112358132134558914423337761098715972584418167651094617711286",
);
}
使用6个轨道解密数字字符串。
rust
#[test]
/// 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, "古びの池飛込水音蛙む");
}
处理宽字符(日文)的加密。
性能优化版本
考虑性能的优化实现:
rust
pub struct RailFence {
rails: u32,
}
impl RailFence {
pub fn new(rails: u32) -> RailFence {
RailFence { rails }
}
pub fn encode(&self, text: &str) -> String {
if self.rails <= 1 {
return text.to_string();
}
let n = self.rails as usize;
let len = text.chars().count();
// 预分配结果字符串
let mut result = String::with_capacity(len);
// 对于每个轨道,直接计算应该放置哪些字符
let chars: Vec<char> = text.chars().collect();
for rail in 0..n {
let mut pos = rail;
let mut down = rail != n - 1;
let mut up = rail != 0;
while pos < len {
result.push(chars[pos]);
if down && up {
// 中间轨道,交替方向
pos += 2 * (n - 1 - rail);
std::mem::swap(&mut down, &mut up);
} else if down {
// 底部轨道,只向上
pos += 2 * (n - 1 - rail);
} else {
// 顶部轨道,只向下
pos += 2 * rail;
}
}
}
result
}
pub fn decode(&self, cipher: &str) -> String {
if self.rails <= 1 {
return cipher.to_string();
}
let n = self.rails as usize;
let len = cipher.chars().count();
let cipher_chars: Vec<char> = cipher.chars().collect();
// 预分配结果
let mut result = vec![' '; len];
// 计算每个轨道的长度
let mut rail_lengths = vec![0; n];
let mut rail = 0;
let mut step = 1;
for _ in 0..len {
rail_lengths[rail] += 1;
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
// 构建每个轨道的字符索引
let mut rail_chars: Vec<Vec<char>> = vec![Vec::new(); n];
let mut start = 0;
for i in 0..n {
let end = start + rail_lengths[i];
rail_chars[i] = cipher_chars[start..end].to_vec();
start = end;
}
// 重新构建明文
let mut rail_indices = vec![0; n];
rail = 0;
let mut step = 1;
let mut pos = 0;
while pos < len {
result[pos] = rail_chars[rail][rail_indices[rail]];
rail_indices[rail] += 1;
pos += 1;
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
result.iter().collect()
}
}
// 使用字节操作的版本(仅适用于ASCII字符)
pub struct RailFenceBytes {
rails: u32,
}
impl RailFenceBytes {
pub fn new(rails: u32) -> RailFenceBytes {
RailFenceBytes { rails }
}
pub fn encode(&self, text: &str) -> String {
if self.rails <= 1 || !text.is_ascii() {
return text.to_string();
}
let n = self.rails as usize;
let bytes = text.as_bytes();
let len = bytes.len();
let mut result = Vec::with_capacity(len);
let mut rails: Vec<Vec<u8>> = vec![Vec::new(); n];
let mut rail = 0;
let mut step = 1;
for &byte in bytes {
rails[rail].push(byte);
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
for rail_content in rails {
result.extend(rail_content);
}
String::from_utf8(result).unwrap_or_else(|_| text.to_string())
}
pub fn decode(&self, cipher: &str) -> String {
if self.rails <= 1 || !cipher.is_ascii() {
return cipher.to_string();
}
let n = self.rails as usize;
let len = cipher.as_bytes().len();
let bytes = cipher.as_bytes();
// 计算每个轨道的字符数量
let mut rail_lengths = vec![0; n];
let mut rail = 0;
let mut step = 1;
for _ in 0..len {
rail_lengths[rail] += 1;
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
// 将密文分割到各个轨道
let mut rails: Vec<&[u8]> = Vec::with_capacity(n);
let mut start = 0;
for &length in &rail_lengths {
let end = start + length;
rails.push(&bytes[start..end]);
start = end;
}
// 重新构建明文
let mut result = Vec::with_capacity(len);
let mut rail_indices = vec![0; n];
rail = 0;
step = 1;
for _ in 0..len {
result.push(rails[rail][rail_indices[rail]]);
rail_indices[rail] += 1;
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
String::from_utf8(result).unwrap_or_else(|_| cipher.to_string())
}
}
错误处理和边界情况
考虑更多边界情况的实现:
rust
#[derive(Debug, PartialEq)]
pub enum RailFenceError {
InvalidRails,
EmptyText,
}
impl std::fmt::Display for RailFenceError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
RailFenceError::InvalidRails => write!(f, "轨道数必须大于0"),
RailFenceError::EmptyText => write!(f, "文本不能为空"),
}
}
}
impl std::error::Error for RailFenceError {}
pub struct RailFence {
rails: u32,
}
impl RailFence {
pub fn new(rails: u32) -> Result<RailFence, RailFenceError> {
if rails == 0 {
Err(RailFenceError::InvalidRails)
} else {
Ok(RailFence { rails })
}
}
pub fn encode(&self, text: &str) -> String {
if text.is_empty() {
return String::new();
}
if self.rails <= 1 {
return text.to_string();
}
let n = self.rails as usize;
let mut rails: Vec<String> = vec![String::new(); n];
let mut rail = 0;
let mut step = 1;
for c in text.chars() {
rails[rail].push(c);
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
rails.concat()
}
pub fn decode(&self, cipher: &str) -> String {
if cipher.is_empty() {
return String::new();
}
if self.rails <= 1 {
return cipher.to_string();
}
let n = self.rails as usize;
let len = cipher.chars().count();
// 计算每个轨道的字符数量
let mut rail_lengths = vec![0; n];
let mut rail = 0;
let mut step = 1;
for _ in 0..len {
rail_lengths[rail] += 1;
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
// 将密文分割到各个轨道
let chars: Vec<char> = cipher.chars().collect();
let mut rails: Vec<&[char]> = Vec::with_capacity(n);
let mut start = 0;
for &length in &rail_lengths {
let end = start + length;
rails.push(&chars[start..end]);
start = end;
}
// 重新构建明文
let mut result = String::with_capacity(len);
let mut rail_indices = vec![0; n];
rail = 0;
let mut step = 1;
for _ in 0..len {
result.push(rails[rail][rail_indices[rail]]);
rail_indices[rail] += 1;
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
result
}
// 返回Result的版本
pub fn encode_safe(&self, text: &str) -> Result<String, RailFenceError> {
if text.is_empty() {
Err(RailFenceError::EmptyText)
} else {
Ok(self.encode(text))
}
}
pub fn decode_safe(&self, cipher: &str) -> Result<String, RailFenceError> {
if cipher.is_empty() {
Err(RailFenceError::EmptyText)
} else {
Ok(self.decode(cipher))
}
}
}
// 支持可变轨道数的版本
pub struct DynamicRailFence {
rails: u32,
}
impl DynamicRailFence {
pub fn new(rails: u32) -> DynamicRailFence {
DynamicRailFence { rails }
}
pub fn set_rails(&mut self, rails: u32) {
self.rails = rails;
}
pub fn encode(&self, text: &str) -> String {
let fence = RailFence::new(self.rails).unwrap();
fence.encode(text)
}
pub fn decode(&self, cipher: &str) -> String {
let fence = RailFence::new(self.rails).unwrap();
fence.decode(cipher)
}
}
扩展功能
基于基础实现,我们可以添加更多功能:
rust
pub struct RailFence {
rails: u32,
}
impl RailFence {
pub fn new(rails: u32) -> RailFence {
RailFence { rails }
}
pub fn encode(&self, text: &str) -> String {
if self.rails <= 1 {
return text.to_string();
}
let n = self.rails as usize;
let mut rails: Vec<String> = vec![String::new(); n];
let mut rail = 0;
let mut step = 1;
for c in text.chars() {
rails[rail].push(c);
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
rails.concat()
}
pub fn decode(&self, cipher: &str) -> String {
if self.rails <= 1 {
return cipher.to_string();
}
let n = self.rails as usize;
let len = cipher.chars().count();
let mut rail_lengths = vec![0; n];
let mut rail = 0;
let mut step = 1;
for _ in 0..len {
rail_lengths[rail] += 1;
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
let chars: Vec<char> = cipher.chars().collect();
let mut rails: Vec<&[char]> = Vec::with_capacity(n);
let mut start = 0;
for &length in &rail_lengths {
let end = start + length;
rails.push(&chars[start..end]);
start = end;
}
let mut result = String::with_capacity(len);
let mut rail_indices = vec![0; n];
rail = 0;
let mut step = 1;
for _ in 0..len {
result.push(rails[rail][rail_indices[rail]]);
rail_indices[rail] += 1;
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
result
}
// 分析栅栏密码结构
pub fn analyze(&self, text: &str) -> RailFenceAnalysis {
let encoded = self.encode(text);
let pattern = self.get_rail_pattern(text.len());
RailFenceAnalysis {
original_text: text.to_string(),
encoded_text: encoded,
rail_count: self.rails,
text_length: text.len(),
rail_pattern: pattern,
}
}
// 获取轨道模式
fn get_rail_pattern(&self, length: usize) -> Vec<usize> {
if self.rails <= 1 {
return vec![0; length];
}
let n = self.rails as usize;
let mut pattern = Vec::with_capacity(length);
let mut rail = 0;
let mut step = 1;
for _ in 0..length {
pattern.push(rail);
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
pattern
}
// 获取每个轨道的字符
pub fn get_rail_contents(&self, text: &str) -> Vec<String> {
if self.rails <= 1 {
return vec![text.to_string()];
}
let n = self.rails as usize;
let mut rails: Vec<String> = vec![String::new(); n];
let mut rail = 0;
let mut step = 1;
for c in text.chars() {
rails[rail].push(c);
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
rails
}
}
pub struct RailFenceAnalysis {
pub original_text: String,
pub encoded_text: String,
pub rail_count: u32,
pub text_length: usize,
pub rail_pattern: Vec<usize>,
}
// 栅栏密码工具箱
pub struct RailFenceToolkit;
impl RailFenceToolkit {
pub fn new() -> Self {
RailFenceToolkit
}
// 尝试不同的轨道数进行解密
pub fn brute_force_decode(&self, cipher: &str, max_rails: u32) -> Vec<(u32, String)> {
let mut results = Vec::new();
for rails in 2..=max_rails {
let fence = RailFence::new(rails);
let decoded = fence.decode(cipher);
results.push((rails, decoded));
}
results
}
// 分析密文可能的轨道数
pub fn analyze_rail_count(&self, cipher: &str) -> Vec<u32> {
let len = cipher.chars().count();
let mut possible_rails = Vec::new();
// 轨道数必须在合理范围内
for rails in 2..=((len / 2) as u32 + 1).min(10) {
// 简单启发式检查
if len % (rails as usize) == 0 || len % (rails as usize - 1) == 0 {
possible_rails.push(rails);
}
}
possible_rails
}
// 格式化显示栅栏密码结构
pub fn display_rail_fence(&self, text: &str, rails: u32) -> String {
if rails <= 1 {
return text.to_string();
}
let n = rails as usize;
let chars: Vec<char> = text.chars().collect();
let len = chars.len();
// 创建显示网格
let mut grid: Vec<Vec<char>> = vec![vec!['.'; len]; n];
let mut rail = 0;
let mut step = 1;
for (i, &c) in chars.iter().enumerate() {
grid[rail][i] = c;
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
// 格式化输出
grid.iter()
.map(|row| row.iter().collect::<String>())
.collect::<Vec<String>>()
.join("\n")
}
}
// 便利函数
pub fn encode_rail_fence(text: &str, rails: u32) -> String {
let fence = RailFence::new(rails);
fence.encode(text)
}
pub fn decode_rail_fence(cipher: &str, rails: u32) -> String {
let fence = RailFence::new(rails);
fence.decode(cipher)
}
pub fn format_rail_fence_analysis(text: &str, rails: u32) -> String {
let fence = RailFence::new(rails);
let analysis = fence.analyze(text);
format!(
"原文: {}\n密文: {}\n轨道数: {}\n长度: {}\n轨道模式: {:?}",
analysis.original_text,
analysis.encoded_text,
analysis.rail_count,
analysis.text_length,
analysis.rail_pattern
)
}
实际应用场景
栅栏密码在实际开发中有以下应用:
- 密码学教学:经典密码算法教学和演示
- 游戏开发:解密游戏和益智游戏
- 教育软件:密码学和信息安全教学工具
- 文本处理:特殊文本格式化和处理
- 历史研究:古典密码研究和分析
- 编程练习:算法设计和字符串处理练习
- 安全通信:简单的文本混淆和隐私保护
- 艺术创作:创意文本排版和视觉设计
算法复杂度分析
-
时间复杂度:
- 加密:O(n),其中n是文本长度
- 解密:O(n),其中n是密文长度
-
空间复杂度:O(n)
- 需要存储轨道中的字符和结果字符串
与其他实现方式的比较
rust
// 使用递归的实现
pub struct RailFenceRecursive {
rails: u32,
}
impl RailFenceRecursive {
pub fn new(rails: u32) -> RailFenceRecursive {
RailFenceRecursive { rails }
}
pub fn encode(&self, text: &str) -> String {
fn encode_recursive(
chars: &[char],
rails: usize,
rail: usize,
step: i32,
index: usize,
rail_chars: &mut [String],
) {
if index >= chars.len() {
return;
}
rail_chars[rail].push(chars[index]);
let (new_rail, new_step) = if rail == 0 {
(1, 1)
} else if rail == rails - 1 {
(rails - 2, -1)
} else {
((rail as i32 + step) as usize, step)
};
encode_recursive(chars, rails, new_rail, new_step, index + 1, rail_chars);
}
if self.rails <= 1 {
return text.to_string();
}
let n = self.rails as usize;
let chars: Vec<char> = text.chars().collect();
let mut rails: Vec<String> = vec![String::new(); n];
encode_recursive(&chars, n, 0, 1, 0, &mut rails);
rails.concat()
}
}
// 使用第三方库的实现
// [dependencies]
// itertools = "0.10"
use itertools::Itertools;
pub struct RailFenceItertools {
rails: u32,
}
impl RailFenceItertools {
pub fn new(rails: u32) -> RailFenceItertools {
RailFenceItertools { rails }
}
pub fn encode(&self, text: &str) -> String {
if self.rails <= 1 {
return text.to_string();
}
let n = self.rails as usize;
let mut rails: Vec<Vec<char>> = vec![Vec::new(); n];
let mut rail = 0;
let mut step = 1;
for c in text.chars() {
rails[rail].push(c);
if rail == 0 {
step = 1;
} else if rail == n - 1 {
step = -1;
}
rail = (rail as i32 + step) as usize;
}
rails.into_iter().flatten().collect()
}
}
// 使用状态机的实现
#[derive(Debug, Clone, Copy)]
enum RailDirection {
Down,
Up,
}
pub struct RailFenceStateMachine {
rails: u32,
}
impl RailFenceStateMachine {
pub fn new(rails: u32) -> RailFenceStateMachine {
RailFenceStateMachine { rails }
}
pub fn encode(&self, text: &str) -> String {
if self.rails <= 1 {
return text.to_string();
}
let n = self.rails as usize;
let mut rails: Vec<String> = vec![String::new(); n];
let mut current_rail = 0;
let mut direction = RailDirection::Down;
for c in text.chars() {
rails[current_rail].push(c);
match direction {
RailDirection::Down => {
if current_rail == n - 1 {
direction = RailDirection::Up;
current_rail = n - 2;
} else {
current_rail += 1;
}
}
RailDirection::Up => {
if current_rail == 0 {
direction = RailDirection::Down;
current_rail = 1;
} else {
current_rail -= 1;
}
}
}
}
rails.concat()
}
}
总结
通过 rail-fence-cipher 练习,我们学到了:
- 字符串处理:掌握了复杂的字符串处理和字符重排技巧
- 算法设计:学会了实现Z字形模式的算法设计
- 结构体设计:理解了如何设计合适的数据结构存储状态
- 索引计算:深入理解了复杂索引模式的计算方法
- 性能优化:学会了预分配内存和使用高效算法等优化技巧
- 边界处理:理解了如何处理各种边界情况
这些技能在实际开发中非常有用,特别是在密码学、文本处理、游戏开发等场景中。栅栏密码虽然是一个经典的密码学问题,但它涉及到了字符串处理、算法设计、索引计算、性能优化等许多核心概念,是学习Rust实用编程的良好起点。
通过这个练习,我们也看到了Rust在字符串处理和算法实现方面的强大能力,以及如何用安全且高效的方式实现经典的密码学算法。这种结合了安全性和性能的语言特性正是Rust的魅力所在。