科学家们发现,即使一个单词的第一个字母和最后一个字母在正确的位置,文本仍然可以被阅读。单词中剩余的字符可以随机排列。
假设您希望发送一个文本,其内容由筛选器检查特定的单词。而不是加密,我们也可以使用这个算法。但实际上那只是个有趣的节目。
我想知道专业人士如何评价我的代码。你能写一些更易读的源代码吗?
Sntecistis hvae fnuod taht a txet can sltil be read eevn if only the fsrit and lsat
lteter of a wrod are in teihr rghit plcae. The rinnimaeg caartcehrs witihn the wrod
can be araergnd rdnlomay.
Sppuose you want to sned a text wsohe cnteont is cehcekd for seipcfic wdros by a
ftelir. Intsead of enintrpcyg it, one cuold aslo use this aorltihgm. But aallucty
that's jsut a fun prraogm.
I would like to know how pnarloofesiss rtae my code. Can you wtrie ptars of the
suorce cdoe mroe rabdleae?iormpt jvaa.uitl.Scenanr;
imorpt java.io.Flie;
improt jvaa.io.FdeliRaeer;
import jvaa.io.BfeaeudfeRrder;
ipomrt java.io.IxptiEeOcon;
pilubc cslas Main {
pilubc siattc viod main(String[] args) {
SignldetrBuir text = new SeuitdrBginlr();
if (agrs.lgenth == 0) {
Senacnr scennar = new Snenacr(Syestm.in);
text.aeppnd(snncear.niLxtnee());
} esle if (args[0].conatnis("-help")) {
Stysem.out.pirlntn("Jsut clal it lkie taht: java Main");
Seytsm.out.ptnlirn("Or povirde a txt-file: java Main file.txt");
Sestym.exit(0);
} esle {
// read whloe file in Sntirg
File file = new File(args[0]);
try (BeafedurfRdeer br = new BerfuReeadedfr(new FadleeReir(flie))) {
Snritg lnie;
wihle ((line = br.rLniadee()) != null) {
text.apnepd(lnie + "\n");
}
} ccath (IOtExeocipn e) {
e.pacttSTcnrrkiae();
}
}
TeuCxeosfntr tc = new TsCxtofenuer(txet.totnriSg());
tc.cnufsoe();
Setsym.out.priltnn(tc.gTdoxseCfneutet());
}
}import java.util.Scanner;
import java.io.File;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
StringBuilder text = new StringBuilder();
if (args.length == 0) {
Scanner scanner = new Scanner(System.in);
text.append(scanner.nextLine());
} else if (args[0].contains("-help")) {
System.out.println("Just call it like that: java Main");
System.out.println("Or provide a txt-file: java Main file.txt");
System.exit(0);
} else {
// read whole file in String
File file = new File(args[0]);
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
text.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
}
}
TextConfuser tc = new TextConfuser(text.toString());
tc.confuse();
System.out.println(tc.getConfusedText());
}
}import java.util.List;
import java.util.ArrayList;
import java.util.Random;
public class TextConfuser {
private String text;
private List<String> words;
private StringBuilder confusedText;
public TextConfuser(String text) {
this.text = text;
this.words = new ArrayList<String>();
this.confusedText = new StringBuilder();
}
public void setText(String text) {
this.text = text;
this.confusedText = new StringBuilder();
}
public String getText() {
return text;
}
public String getConfusedText() {
return confusedText.toString();
}
// make text to a list of words for further processing
public void parse() {
// a word can be a word like you know it from natural language
// special symbols like punctuation characters and control characters are treated as own words
words = new ArrayList<String>();
char[] characters = text.toCharArray();
StringBuilder currentWord = new StringBuilder();
for (int i = 0; i < characters.length; i++) {
if (Character.isLetter(characters[i])) {
currentWord.append(characters[i]);
} else {
if (currentWord.length() > 0) {
words.add(currentWord.toString());
currentWord = new StringBuilder();
}
words.add(Character.toString(characters[i]));
}
}
StringBuilder result = new StringBuilder();
for (String word : words) {
result.append(word);
}
}
public void confuse() {
parse();
for (String word : words) {
if (word.length() > 3) {
// get first and last character
char firstChar = word.charAt(0);
char lastChar = word.charAt(word.length() - 1);
// get list of characters between first and last character
List<Character> chars = new ArrayList<>();
for (int i = 1; i < word.length() - 1; i++) {
chars.add(word.charAt(i));
}
// construct confused word
StringBuilder confusedWord = new StringBuilder();
confusedWord.append(firstChar);
while (!chars.isEmpty()) {
Random random = new Random();
Character randomChar = chars.get(random.nextInt(chars.size()));
chars.remove(randomChar);
confusedWord.append(randomChar);
}
confusedWord.append(lastChar);
confusedText.append(confusedWord);
} else {
confusedText.append(word);
}
}
}
}发布于 2019-03-05 21:20:20
我的回答将集中在TextConfuser类的公共API上。
您选择将文本、单词列表和混乱的文本变成该类的字段,因此给定的TextConfuser一次只能对一个文本进行操作,这意味着用户将为给定的文本创建一个TextConfuser,并让它计算混乱的结果。对于下一个文本,他将创建一个新的TextConfuser实例,这绝对是一个有效的生命周期模式。
不适合这个生命周期的是通过setText()方法更改文本的可能性--您应该删除该方法。如果您希望一个TextConfuser能够转换更多的文本,我将推荐一组完全不同的公共方法(请参阅下面的进一步内容)。
然后,您的API迫使用户按照三步顺序获得结果:
TextConfuser tc = new TextConfuser(input);
tc.confuse();
String result = tc.getConfusedText();这很容易出错:如果您的用户忘记了tc.confuse()步骤,他就会得到一个空的结果,而不会注意到他做错了什么。
我希望能把它减少到
TextConfuser tc = new TextConfuser(input);
String result = tc.getConfusedText();如何实现这一目标有两种方法:
confuse(),这样您就可以立即得到可用的结果(我显然不能建议这样做,因为有些开发人员不喜欢构造函数做“真正的工作”)。getConfusedText()方法检查结果是否已经可用(如果没有调用confuse() ),并返回该结果。然后,只在类中使用的方法应该声明为private。这适用于parse() (如果您遵循我的建议,也适用于confuse() )。拥有用户无意调用的公共方法只会使用户感到困惑。
允许将TextConfuser用于多个文本(即使在多个并行线程中)的另一种API是:
public TextConfuser() {...}
public String getConfusedText(String input) {...}您可以消除字段,而是在私有方法(如text ())之间传递words、parse()和confusedText:
private List<String> parse(String input) {...}
private String confuse(List<String> words) {...}然后,您的用户可以做如下的事情
TextConfuser tc = new TextConfuser();
String result1 = tc.getConfusedText("I would like to know how professionals rate my code.");
String result2 = tc.getConfusedText("But actually that's just a fun program.");就我个人而言,比起第一种,我更喜欢这种用法。
对于遵循命名约定,(主要是)正确地缩进代码,选择有用的变量和方法名称,竖起大拇指。
有一些改进是可能的:
这里有一个Collections.shuffle()方法,您可以用它来代替您的洗牌while循环。
setText()方法不重置words字段,它使TextConfuser处于text和words不匹配的混乱状态。
小片段
StringBuilder result = new StringBuilder();
for (String word : words) {
result.append(word);
}没有用途,因为您在任何地方都不使用result变量。
您的一些评论应该成为JavaDoc,特别是用于描述公共方法:
/**
* make text to a list of words for further processing.
* A word can be a word like you know it from natural language.
* Special symbols like punctuation characters and control characters are treated as own words
*/
public void parse() { ... }发布于 2019-03-06 07:38:17
我想知道专业人士如何评价我的代码
对不起,让你失望了:P,但是也许有一些人认为,在我的脑海中,总有一天会帮助你。本综述是对@Ralf Kleberhoff的补充
当我跑的时候
public static void main(String[] args) {
TextConfuser textConfuser = new TextConfuser("Excellent Sir");
textConfuser.parse();
textConfuser.confuse();
System.out.println(textConfuser.getConfusedText());
}最后一个字消失了。
Elenxeclt 与两次指定对象的类型不同,只要编译器能够从上下文中推断类型,就可以指定菱形操作符<>。因此,在实例化对象时可以使用菱形操作符。
在您的代码库中
this.words =新ArrayList() words =新ArrayList();
如果您使用的是Java 7+,那么只需编写new ArrayList<>()即可。
同时(!chars.isEmpty()) {随机随机=新随机();// .}
这个while-循环为chars中的每个元素创建了一个新的Random实例。最好是将初始化挂在while循环之上,只初始化一次。
Random random = new Random();
while (!chars.isEmpty()) {
// ..
}罗伯特·C·马丁( Robert C. Martin )写了一本书“清洁代码”(Clean),还有更多令人悲伤的书。
您的注释做得很好,并将它们分组为逻辑单元,但是我们可以将这些逻辑单元提取到它们自己的方法中。
public void confuse() {
parse();
for (String word : words) {
if (word.length() > 3) {
char firstChar = extractFirstCharacter(word);
char lastChar = extractLastCharacter(word);
List<Character> chars = extractCharactersBetweenFirstAndLastCharacter(word);
StringBuilder confusedWord = constructConfusedWordBy(chars);
confusedText.append(confusedWord);
} else {
confusedText.append(word);
}
}
}原始痴迷是使用原始数据类型来表示领域思想。例如,我们使用字符串来表示消息...。
我们原始的痴迷是word。它来自String类型,我们可以轻松地创建一个新的类Word,它将是一个值对象。
对象的全部意义在于,它们是一种将数据与该数据上使用的进程一起打包的技术。经典的代码气味是一种方法,它似乎更感兴趣的是一个类,而不是它所在的类。
这句话意味着在我们的例子中,TextConfuser更忙于操作一个word来混淆空洞语句。
public void confuse() {
parse();
for (Word word : words) {
Word confused = word.randomizeReadable();
confusedText.append(confused.get())
}
}randomizeReadable on Word方法具有如何操作字符串的孔逻辑。
发布于 2019-03-06 07:43:48
https://codereview.stackexchange.com/questions/214763
复制相似问题