java - Vigenere 密码,同时保持空间并仅加密以辅音字母开头的单词 [Java]
问题描述
我正在尝试编写一个程序,该程序将使用 Vigenere 密码加密一个句子,但只有以辅音字母开头的单词,同时存储空格。我对Java还不是很好,但是我写了一个方法来加密任何给定的单词(所有小写字母)我曾认为使用数组在需要的地方打印空格并忽略以元音开头的单词就足够了,但这样做实际上是每当我打印数组的第二个单词左右时给我错误的输出。有人可以指导我做错了什么吗?有没有更好的方法来做到这一点?到目前为止,这是我的代码:
public class Main {
public static void main(String[] args) {
Scanner u = new Scanner(System.in);
final String k = u.next();
u.nextLine();
String message = u.nextLine();
String[] f = message.split(" ");
System.out.println(encipher(message,k));
for (String s : f) {
if (s.charAt(0) == 'a' || s.charAt(0) == 'e' || s.charAt(0) == 'i' ||
s.charAt(0) == 'o' || s.charAt(0) == 'u') {
System.out.println(s);
} else {
System.out.println(encipher(s, k));
}
}
}
public static String encipher(String message, final String key)
{
String output = "";
for (int x = 0, y = 0; x < message.length(); x++)
{
char c = message.charAt(x);
if (c < 'a' || c > 'z')
continue;
output += (char) ((c + key.charAt(y) - 2 * 'a') % 26 + 'a');
y = ++y % key.length();
}
return output;
}}
您可以看到正常输出(忽略空格和元音/辅音)和数组输出之间的差异。对于字符串键obi和字符串消息“olimpiada brasileira de informatica”,它应该打印“olimpiada psigjtsjzo em informatica”,但在数组中打印“olimpiada psigjtsjzo rf informatica”[暂时忽略打印行的事情,我会在我修复它获得正确的加密]
解决方案
逐字应用加密时,会为每个单词重置密钥,并使用以下"de"
命令进行加密"ob"
:
brasileira
obiobiobio
de
ob
当整个消息被加密时,密钥不会被重置("olimpiada"
有 9 个可以被 整除的字母"obi".length() == 3
),并"de"
用 加密"bi"
:
olimpiada brasileira de informatica
obiobiobi obiobiobio bi obiobiobiob
因此,如果可能需要以某种方式记住y
索引,或者应该实现另一种方法来在下一个索引处的非空白键中提供一个字符:
private static Map<String, Integer> keyIndexes = new HashMap<>();
private static char getNextPosition(String key) {
return key.charAt(keyIndexes.compute(
key, (k, v) -> v == null ? 0 : (v + 1) % k.length()
));
}
private static void resetKey(String key) {
keyIndexes.remove(key);
}
然后该方法encipher
可以更新为:
public static String encipher(String message, final String key)
{
StringBuilder output = new StringBuilder();
for (char c : message.toCharArray())
{
if (c < 'a' || c > 'z')
continue; // skip non-letters
output.append((char) ((c + getNextPosition(key) - 2 * 'a') % 26 + 'a'));
}
return output.toString();
}
测试:
String message = "olimpiada brasileira de informatica";
String k = "obi";
System.out.println(encipher(message, k));
// !!!
resetKey(k);
for (String s : message.split(" ")) {
if (s.matches("[aeiou]\\w*")) { // use regexp to detect a word starting with a vowel
System.out.println(s);
} else {
System.out.println(encipher(s, k));
}
}
输出:
cmqaqqoeipsigjtsjzoemwoncsuouqqb // full message, spaces skipped
olimpiada
psigjtsjzo
em
informatica
如果需要保留非字母和以元音开头的单词作为整个消息(不仅仅是单个单词),则应添加几个标志来跟踪当前字符是否在单词中,如果第一个已检测到元音:
public static String encipherWork(String message, final String key) {
StringBuilder output = new StringBuilder();
boolean inWord = false;
boolean firstVowel = false;
for (char c : message.toCharArray()) {
if ('a' <= c && c <= 'z') {
if (!inWord) {
firstVowel = (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u');
inWord = true;
}
if (!firstVowel) {
output.append((char) ((c + getNextPosition(key) - 2 * 'a') % 26 + 'a'));
continue;
}
} else {
inWord = false;
firstVowel = false;
}
output.append(c); // print non-enciphered characters
}
return output.toString();
}
此方法的输出:
olimpiada psigjtsjzo em informatica // full message
olimpiada
psigjtsjzo
em
informatica
推荐阅读
- html - 为什么当我在手机或 Safari 上查看我的网页时,我的 CSS 网格和图像弹性框显示空白?
- google-signin - Google 登录返回 SIGN_IN_FAILED 12500 的可能原因
- javascript - 自调用函数会干扰 window.onload,除非
- php - 在 PHP 中搜索 MySQL 中的 JSON 数据
- javascript - 问题在 Javascript 中列出对象属性
- google-bigquery - BigQuery 集群字段用法/值不清楚
- php - 使用 Web 连接器集成到 Quickbooks 时在 QBXML 中使用通配符
- azure-timeseries-insights - Azure 时间序列 - 无法获取数据
- python - 月/年格式的 dateutil 解析器:返回月初
- ibm-watson - 如何在 Watson Assistant 中对随机数进行采样?