Rust 练习册 :Rail Fence Cipher与栅栏密码

栅栏密码(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. 核心要求

  1. 结构体设计:设计 RailFence 结构体存储轨道数
  2. 加密实现:实现按Z字形方式排列字符的加密算法
  3. 解密实现:实现根据密文和轨道数还原明文的解密算法
  4. 字符处理:正确处理各种字符,包括宽字符

2. 技术要点

  1. Z字形模式:理解和实现字符在轨道间的Z字形分布
  2. 索引计算:计算字符在轨道中的位置
  3. 字符串操作:高效处理和重组字符串
  4. 算法设计:设计加密和解密算法

完整实现

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

实际应用场景

栅栏密码在实际开发中有以下应用:

  1. 密码学教学:经典密码算法教学和演示
  2. 游戏开发:解密游戏和益智游戏
  3. 教育软件:密码学和信息安全教学工具
  4. 文本处理:特殊文本格式化和处理
  5. 历史研究:古典密码研究和分析
  6. 编程练习:算法设计和字符串处理练习
  7. 安全通信:简单的文本混淆和隐私保护
  8. 艺术创作:创意文本排版和视觉设计

算法复杂度分析

  1. 时间复杂度

    • 加密:O(n),其中n是文本长度
    • 解密:O(n),其中n是密文长度
  2. 空间复杂度: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 练习,我们学到了:

  1. 字符串处理:掌握了复杂的字符串处理和字符重排技巧
  2. 算法设计:学会了实现Z字形模式的算法设计
  3. 结构体设计:理解了如何设计合适的数据结构存储状态
  4. 索引计算:深入理解了复杂索引模式的计算方法
  5. 性能优化:学会了预分配内存和使用高效算法等优化技巧
  6. 边界处理:理解了如何处理各种边界情况

这些技能在实际开发中非常有用,特别是在密码学、文本处理、游戏开发等场景中。栅栏密码虽然是一个经典的密码学问题,但它涉及到了字符串处理、算法设计、索引计算、性能优化等许多核心概念,是学习Rust实用编程的良好起点。

通过这个练习,我们也看到了Rust在字符串处理和算法实现方面的强大能力,以及如何用安全且高效的方式实现经典的密码学算法。这种结合了安全性和性能的语言特性正是Rust的魅力所在。

相关推荐
东方隐侠安全团队-千里2 小时前
第3节 RSA算法开启公钥加密时代
网络·人工智能·算法
weixin_441455262 小时前
说说Java有哪些集合类
java·开发语言
李趣趣2 小时前
C#中关于ContextMenuStrip批量添加Item的问题
开发语言·c#
7澄12 小时前
深入解析 LeetCode 1:两数之和
算法·leetcode·职场和发展·arraylist
张人玉2 小时前
C# 串口通讯中 SerialPort 类的关键参数和使用方法
开发语言·c#·串口通讯
白山云北诗2 小时前
网站被攻击了怎么办?如何进行DDoS防御?
开发语言·网络安全·php·ddos·防ddos·防cc
Moonbit2 小时前
MGPIC 初赛提交倒计时 4 天!
后端·算法·编程语言
程序定小飞3 小时前
基于springboot的作业管理系统设计与实现
java·开发语言·spring boot·后端·spring
Jonathan Star3 小时前
NestJS 是基于 Node.js 的渐进式后端框架,核心特点包括 **依赖注入、模块化架构、装饰器驱动、TypeScript 优先、与主流工具集成** 等
开发语言·javascript·node.js