用其他字符替换字符
Substituting characters with other characters
我要破译某段文字。当我在字符串中遇到一个字母时,我想用字母表中的下一个字母替换它。然后在下一轮我想用下一个字母替换。
a -> b
k -> l
那么第二轮应该试试
a -> c
k -> m
字符的问题在于它包括各种奇怪的字符,当您遇到 z 并尝试替换它时,它会被替换为一个奇怪的符号。
谁能帮我从 A-Z 做一些循环列表?在下面的代码片段中,我创建了一个包含 a 到 z 的列表。在循环中选择一个字符,搜索它的索引并 'adjusted' 并且应该检索新字符。但它不起作用。 (列表不是循环的原因之一)
public static void decipher(){
String cyphertext = "aVaqrprzoreoeratraWhyvhfraJnygreUbyynaqreqrgjrroebrefinaRqvguZnetbganneNzfgreqnzNaarjvytenntzrrxbzraznnezbrgabtrrarragvwqwrovwbznoyvwiraBznmnyurgzbrvyvwxuroorabzNaarabtrracnnejrxraqnnegrubhqrafpuevwsgRqvguSenaxvarraoevrsnnaTregehqAnhznaauhaiebrtrerohhezrvfwrvaSenaxshegnzZnva";
char[] plaintext = new char[cyphertext.length()];
List<Character> a2z = new ArrayList<Character>(26);
for (char c = 'A'; c <= 'Z'; c++){
a2z.add(Character.valueOf(c));
}
for(int i = 1; i < 26; i++){
for(int j = 0; j < cyphertext.length(); j++){
char currentChar = cyphertext.charAt(j);
int newCharIndex = a2z.indexOf(currentChar)+i;
plaintext[j] = a2z.get(newCharIndex);
}
}
}
问题出在这里:
int newCharIndex = a2z.indexOf(currentChar)+i;
plaintext[j] = a2z.get(newCharIndex);
这里的解码字符是0到25之间,Ascii的A-Z是从65到90,你想把a2z
中的索引移到A到Z的范围内:
plaintext[j] = a2z.get(newCharIndex) + 'A';
如果我没理解错的话,你希望替换密码将字母向上移动 N,从 Z
换行到 A
,同时进行大写和小写字母,然后保留所有其他字符不变。
例如如果 N 为 2:
a → c b → d ... x → z y → a z → b
A → C B → D ... X → Z Y → A Z → B
像这样?
char[] text = "aVaqrprzoreoeratraWhyvhfraJnygreUbyynaqreqrgjrroebrefinaRqvguZnetbganneNzfgreqnzNaarjvytenntzrrxbzraznnezbrgabtrrarragvwqwrovwbznoyvwiraBznmnyurgzbrvyvwxuroorabzNaarabtrracnnejrxraqnnegrubhqrafpuevwsgRqvguSenaxvarraoevrsnnaTregehqAnhznaauhaiebrtrerohhezrvfwrvaSenaxshegnzZnva".toCharArray();
for (int n = 1; n < 26; n++) {
for (int i = 0; i < text.length; i++) {
char c = text[i];
if (c >= 'A' && c <= 'Z')
text[i] = (char)('A' + (c - 'A' + n) % 26);
else if (c >= 'a' && c <= 'z')
text[i] = (char)('a' + (c - 'a' + n) % 26);
}
}
System.out.println(new String(text));
输出
nIndecemberbrengenJuliusenWalterHollanderdetweebroersvanEdithMargotnaarAmsterdamAnnewilgraagmeekomenmaarmoetnogeeneentijdjebijomablijvenOmazalhetmoeilijkhebbenomAnnenogeenpaarwekendaartehoudenschrijftEdithFrankineenbriefaanGertrudNaumannhunvroegerebuurmeisjeinFrankfurtamMain
当然,您确实意识到移动 1,然后移动 2,然后移动 3,...最后移动 26,与移动一次(1 + 2 + 3 + ... + 26), 即 351, 351 % 26 = 13
.
并且移位13意味着编码和解码是相同的操作。
说明
如果你移动 26,你移动了整整一轮,即 a → a b → b ...
,所以这与不移动相同,因此 N >= 26 的任何移动都与 N % 26 相同,例如N = 28
等同于 N = 2
.
移位 1 a → b
然后移位 2 b → d
然后移位 3 d → g
,与移位 1+2+3=6 a → g
相同.所以 1+2+...+26=351 的移动与 351% 26 = 13.
的移动相同
如果变量 c
是一个大写字母 (A-Z),那么 c - 'A'
是一个介于 0 和 25 之间的数字。添加一个 6 的示例移位,你得到一个数字 6-31。求余数 26 (% 26
) 得到 6-25,0-5 然后 + 'A'
得到 G-Z,A-F
,意思是 A → G B → H ... Y → E Z → F
,每个字母移动 6.
小写字母也一样。
您不需要循环列表来处理边缘情况。此外,您应该记住字符 A-Z
的 ascii 值介于 65-90 和 a-z
之间的 97-122 之间。您可以创建两个循环列表,但不需要它们,因为边缘情况很容易处理:
public static void main(String[] args) {
String cyphertext = "aVaqrprzoreoeratraWhyvhfraJnygreUbyynaqreqrgjrroebrefinaRqvguZnetbganneNzfgreqnzNaarjvytenntzrrxbzraznnezbrgabtrrarragvwqwrovwbznoyvwiraBznmnyurgzbrvyvwxuroorabzNaarabtrracnnejrxraqnnegrubhqrafpuevwsgRqvguSenaxvarraoevrsnnaTregehqAnhznaauhaiebrtrerohhezrvfwrvaSenaxshegnzZnva";
char[] plaintext = new char[cyphertext.length()];
// first shift
shiftLetters(cyphertext, plaintext, 1);
// update cyphertext with the intermediate result
cyphertext = new String(plaintext);
// second shift
shiftLetters(cyphertext, plaintext, 2);
// print result
System.out.println(new String(plaintext));
}
private static void shiftLetters(String cyphertext, char[] plaintext, int shifts) {
for (int i=0; i<cyphertext.length(); i++){
int tmp = cyphertext.charAt(i) + shifts;
tmp = handleEdgeCases(tmp);
plaintext[i] = (char)(tmp);
}
}
// here we handle the "circular" cases
private static int handleEdgeCases(int tmp) {
if (tmp > 90 && tmp < 97) {
tmp = tmp - 90 + 65;
} else if (tmp > 122) {
tmp = tmp - 122 + 97;
}
return tmp;
}
我要破译某段文字。当我在字符串中遇到一个字母时,我想用字母表中的下一个字母替换它。然后在下一轮我想用下一个字母替换。
a -> b
k -> l
那么第二轮应该试试
a -> c
k -> m
字符的问题在于它包括各种奇怪的字符,当您遇到 z 并尝试替换它时,它会被替换为一个奇怪的符号。
谁能帮我从 A-Z 做一些循环列表?在下面的代码片段中,我创建了一个包含 a 到 z 的列表。在循环中选择一个字符,搜索它的索引并 'adjusted' 并且应该检索新字符。但它不起作用。 (列表不是循环的原因之一)
public static void decipher(){
String cyphertext = "aVaqrprzoreoeratraWhyvhfraJnygreUbyynaqreqrgjrroebrefinaRqvguZnetbganneNzfgreqnzNaarjvytenntzrrxbzraznnezbrgabtrrarragvwqwrovwbznoyvwiraBznmnyurgzbrvyvwxuroorabzNaarabtrracnnejrxraqnnegrubhqrafpuevwsgRqvguSenaxvarraoevrsnnaTregehqAnhznaauhaiebrtrerohhezrvfwrvaSenaxshegnzZnva";
char[] plaintext = new char[cyphertext.length()];
List<Character> a2z = new ArrayList<Character>(26);
for (char c = 'A'; c <= 'Z'; c++){
a2z.add(Character.valueOf(c));
}
for(int i = 1; i < 26; i++){
for(int j = 0; j < cyphertext.length(); j++){
char currentChar = cyphertext.charAt(j);
int newCharIndex = a2z.indexOf(currentChar)+i;
plaintext[j] = a2z.get(newCharIndex);
}
}
}
问题出在这里:
int newCharIndex = a2z.indexOf(currentChar)+i;
plaintext[j] = a2z.get(newCharIndex);
这里的解码字符是0到25之间,Ascii的A-Z是从65到90,你想把a2z
中的索引移到A到Z的范围内:
plaintext[j] = a2z.get(newCharIndex) + 'A';
如果我没理解错的话,你希望替换密码将字母向上移动 N,从 Z
换行到 A
,同时进行大写和小写字母,然后保留所有其他字符不变。
例如如果 N 为 2:
a → c b → d ... x → z y → a z → b
A → C B → D ... X → Z Y → A Z → B
像这样?
char[] text = "aVaqrprzoreoeratraWhyvhfraJnygreUbyynaqreqrgjrroebrefinaRqvguZnetbganneNzfgreqnzNaarjvytenntzrrxbzraznnezbrgabtrrarragvwqwrovwbznoyvwiraBznmnyurgzbrvyvwxuroorabzNaarabtrracnnejrxraqnnegrubhqrafpuevwsgRqvguSenaxvarraoevrsnnaTregehqAnhznaauhaiebrtrerohhezrvfwrvaSenaxshegnzZnva".toCharArray();
for (int n = 1; n < 26; n++) {
for (int i = 0; i < text.length; i++) {
char c = text[i];
if (c >= 'A' && c <= 'Z')
text[i] = (char)('A' + (c - 'A' + n) % 26);
else if (c >= 'a' && c <= 'z')
text[i] = (char)('a' + (c - 'a' + n) % 26);
}
}
System.out.println(new String(text));
输出
nIndecemberbrengenJuliusenWalterHollanderdetweebroersvanEdithMargotnaarAmsterdamAnnewilgraagmeekomenmaarmoetnogeeneentijdjebijomablijvenOmazalhetmoeilijkhebbenomAnnenogeenpaarwekendaartehoudenschrijftEdithFrankineenbriefaanGertrudNaumannhunvroegerebuurmeisjeinFrankfurtamMain
当然,您确实意识到移动 1,然后移动 2,然后移动 3,...最后移动 26,与移动一次(1 + 2 + 3 + ... + 26), 即 351, 351 % 26 = 13
.
并且移位13意味着编码和解码是相同的操作。
说明
如果你移动 26,你移动了整整一轮,即 a → a b → b ...
,所以这与不移动相同,因此 N >= 26 的任何移动都与 N % 26 相同,例如N = 28
等同于 N = 2
.
移位 1 a → b
然后移位 2 b → d
然后移位 3 d → g
,与移位 1+2+3=6 a → g
相同.所以 1+2+...+26=351 的移动与 351% 26 = 13.
如果变量 c
是一个大写字母 (A-Z),那么 c - 'A'
是一个介于 0 和 25 之间的数字。添加一个 6 的示例移位,你得到一个数字 6-31。求余数 26 (% 26
) 得到 6-25,0-5 然后 + 'A'
得到 G-Z,A-F
,意思是 A → G B → H ... Y → E Z → F
,每个字母移动 6.
小写字母也一样。
您不需要循环列表来处理边缘情况。此外,您应该记住字符 A-Z
的 ascii 值介于 65-90 和 a-z
之间的 97-122 之间。您可以创建两个循环列表,但不需要它们,因为边缘情况很容易处理:
public static void main(String[] args) {
String cyphertext = "aVaqrprzoreoeratraWhyvhfraJnygreUbyynaqreqrgjrroebrefinaRqvguZnetbganneNzfgreqnzNaarjvytenntzrrxbzraznnezbrgabtrrarragvwqwrovwbznoyvwiraBznmnyurgzbrvyvwxuroorabzNaarabtrracnnejrxraqnnegrubhqrafpuevwsgRqvguSenaxvarraoevrsnnaTregehqAnhznaauhaiebrtrerohhezrvfwrvaSenaxshegnzZnva";
char[] plaintext = new char[cyphertext.length()];
// first shift
shiftLetters(cyphertext, plaintext, 1);
// update cyphertext with the intermediate result
cyphertext = new String(plaintext);
// second shift
shiftLetters(cyphertext, plaintext, 2);
// print result
System.out.println(new String(plaintext));
}
private static void shiftLetters(String cyphertext, char[] plaintext, int shifts) {
for (int i=0; i<cyphertext.length(); i++){
int tmp = cyphertext.charAt(i) + shifts;
tmp = handleEdgeCases(tmp);
plaintext[i] = (char)(tmp);
}
}
// here we handle the "circular" cases
private static int handleEdgeCases(int tmp) {
if (tmp > 90 && tmp < 97) {
tmp = tmp - 90 + 65;
} else if (tmp > 122) {
tmp = tmp - 122 + 97;
}
return tmp;
}