C#实现Playfair密码:矩阵位置逆置换功能技术求助
别慌!我来帮你一步步搞定这个Playfair密码的变种实现,咱们把问题拆成几个小模块,逐个击破就简单多了~
实现步骤拆解
咱们的需求可以分成四个核心环节:生成无重复字符集、构建5×5矩阵、快速查找字符位置、消息字符替换。下面逐个讲清楚代码怎么写:
1. 生成密钥+消息的无重复字符集
首先要把密钥和消息合并,过滤掉非字母字符,然后去重。如果字符数不够25个,还要补充剩下的字母(注意:传统Playfair会把I和J合并,如果你需要这个规则,可以在代码里加个判断把J替换成I,我会在注释里标出来)。
private static List<char> GenerateUniqueCharSet(string key, string message) { // 统一转为大写,避免大小写干扰 string combinedContent = (key + message).ToUpperInvariant(); HashSet<char> uniqueChars = new HashSet<char>(); List<char> charSet = new List<char>(); foreach (char c in combinedContent) { // 只保留字母字符 if (char.IsLetter(c)) { // 可选:合并I和J,把J替换成I // char processedChar = c == 'J' ? 'I' : c; char processedChar = c; // HashSet.Add返回bool,只有字符不存在时才添加到列表 if (uniqueChars.Add(processedChar)) { charSet.Add(processedChar); } } } // 补充剩余字母,凑够25个 for (char c = 'A'; c <= 'Z'; c++) { // 可选:如果合并I/J,跳过J // if (c == 'J') continue; if (!uniqueChars.Contains(c)) { charSet.Add(c); if (charSet.Count == 25) break; } } return charSet; }
2. 构建5×5二维矩阵
把上面生成的无重复字符集,按行优先的顺序填充到5×5数组里就行:
private static char[,] BuildPlayfairMatrix(List<char> charSet) { char[,] playfairMatrix = new char[5, 5]; int charIndex = 0; for (int row = 0; row < 5; row++) { for (int col = 0; col < 5; col++) { playfairMatrix[row, col] = charSet[charIndex++]; } } return playfairMatrix; }
3. 构建字符-位置映射字典
为了避免每次查找字符位置都遍历整个矩阵(效率太低),咱们提前做一个字典,记录每个字符对应的(行, 列)坐标,这样查找就是O(1)的速度:
private static Dictionary<char, (int row, int col)> BuildCharPositionMap(char[,] matrix) { Dictionary<char, (int row, int col)> positionMap = new Dictionary<char, (int row, int col)>(); for (int row = 0; row < 5; row++) { for (int col = 0; col < 5; col++) { char currentChar = matrix[row, col]; if (!positionMap.ContainsKey(currentChar)) { positionMap[currentChar] = (row, col); } } } return positionMap; }
4. 处理消息,替换为逆序位置的字符
遍历消息里的每个字符,找到它的位置(row, col),然后取矩阵里(col, row)位置的字符作为替换值。非字母字符可以选择保留或者过滤,这里我做了保留处理:
private static string TransformMessage(string message, char[,] matrix, Dictionary<char, (int row, int col)> positionMap) { StringBuilder resultBuilder = new StringBuilder(); string upperMessage = message.ToUpperInvariant(); foreach (char c in upperMessage) { if (!char.IsLetter(c)) { // 保留非字母字符(比如空格、标点),不需要转换 resultBuilder.Append(c); continue; } // 可选:如果合并I/J,把消息里的J转成I再查找 // char lookupChar = c == 'J' ? 'I' : c; char lookupChar = c; if (positionMap.TryGetValue(lookupChar, out var charPosition)) { // 核心操作:原位置(row, col) → 逆序位置(col, row) char replacementChar = matrix[charPosition.col, charPosition.row]; resultBuilder.Append(replacementChar); } else { // 理论上不会走到这里,因为我们的字符集包含所有字母 resultBuilder.Append(c); } } return resultBuilder.ToString(); }
整合测试示例
把上面的方法放到一个类里,写个Main方法测试效果:
using System; using System.Collections.Generic; using System.Text; class PlayfairTransformer { static void Main(string[] args) { string secretKey = "PLAYFAIR"; string inputMessage = "HELLOWORLD!"; // 按步骤执行 var uniqueCharSet = GenerateUniqueCharSet(secretKey, inputMessage); var playfairMatrix = BuildPlayfairMatrix(uniqueCharSet); var charPositionMap = BuildCharPositionMap(playfairMatrix); string transformedMessage = TransformMessage(inputMessage, playfairMatrix, charPositionMap); // 输出结果 Console.WriteLine("生成的Playfair矩阵:"); PrintMatrix(playfairMatrix); Console.WriteLine($"\n原消息:{inputMessage}"); Console.WriteLine($"转换后消息:{transformedMessage}"); } // 辅助方法:打印矩阵,方便查看 private static void PrintMatrix(char[,] matrix) { for (int row = 0; row < 5; row++) { for (int col = 0; col < 5; col++) { Console.Write(matrix[row, col] + " "); } Console.WriteLine(); } } // 把上面四个方法(GenerateUniqueCharSet、BuildPlayfairMatrix、BuildCharPositionMap、TransformMessage)放在这里 }
额外说明
- I/J合并规则:如果需要遵循传统Playfair的这个规则,只需要在生成字符集和处理消息的代码里,把所有J替换成I就行,我已经在代码里加了注释提示。
- 大小写保留:上面的代码统一转成大写输出,如果需要保留原消息的大小写,可以在遍历的时候记录每个字符的大小写状态,替换后再转回去。
- 非字母处理:如果不需要保留非字母字符,直接跳过就行,把
resultBuilder.Append(c);改成continue;即可。
内容的提问来源于stack exchange,提问作者user9647560
相关产品推荐
相关产品推荐

