首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >混淆文本而不使其不可读

混淆文本而不使其不可读
EN

Code Review用户
提问于 2019-03-05 12:45:29
回答 3查看 592关注 0票数 5

科学家们发现,即使一个单词的第一个字母和最后一个字母在正确的位置,文本仍然可以被阅读。单词中剩余的字符可以随机排列。

假设您希望发送一个文本,其内容由筛选器检查特定的单词。而不是加密,我们也可以使用这个算法。但实际上那只是个有趣的节目。

我想知道专业人士如何评价我的代码。你能写一些更易读的源代码吗?

示例输出

代码语言:javascript
复制
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?

另一个示例

代码语言:javascript
复制
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());
    }
}

,这里是源代码

Main.java

代码语言:javascript
复制
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());
    }
}

Text Confuser.java

代码语言:javascript
复制
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);
            }
        }
    }
}
EN

回答 3

Code Review用户

回答已采纳

发布于 2019-03-05 21:20:20

我的回答将集中在TextConfuser类的公共API上。

API讨论

您选择将文本、单词列表和混乱的文本变成该类的字段,因此给定的TextConfuser一次只能对一个文本进行操作,这意味着用户将为给定的文本创建一个TextConfuser,并让它计算混乱的结果。对于下一个文本,他将创建一个新的TextConfuser实例,这绝对是一个有效的生命周期模式。

不适合这个生命周期的是通过setText()方法更改文本的可能性--您应该删除该方法。如果您希望一个TextConfuser能够转换更多的文本,我将推荐一组完全不同的公共方法(请参阅下面的进一步内容)。

然后,您的API迫使用户按照三步顺序获得结果:

代码语言:javascript
复制
    TextConfuser tc = new TextConfuser(input);
    tc.confuse();
    String result = tc.getConfusedText();

这很容易出错:如果您的用户忘记了tc.confuse()步骤,他就会得到一个空的结果,而不会注意到他做错了什么。

我希望能把它减少到

代码语言:javascript
复制
    TextConfuser tc = new TextConfuser(input);
    String result = tc.getConfusedText();

如何实现这一目标有两种方法:

  • 让构造函数调用confuse(),这样您就可以立即得到可用的结果(我显然不能建议这样做,因为有些开发人员不喜欢构造函数做“真正的工作”)。
  • getConfusedText()方法检查结果是否已经可用(如果没有调用confuse() ),并返回该结果。

然后,只在类中使用的方法应该声明为private。这适用于parse() (如果您遵循我的建议,也适用于confuse() )。拥有用户无意调用的公共方法只会使用户感到困惑。

允许将TextConfuser用于多个文本(即使在多个并行线程中)的另一种API是:

代码语言:javascript
复制
public TextConfuser() {...}
public String getConfusedText(String input) {...}

您可以消除字段,而是在私有方法(如text ())之间传递wordsparse()confusedText

代码语言:javascript
复制
private List<String> parse(String input) {...}
private String confuse(List<String> words) {...}

然后,您的用户可以做如下的事情

代码语言:javascript
复制
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处于textwords不匹配的混乱状态。

小片段

代码语言:javascript
复制
    StringBuilder result = new StringBuilder();
    for (String word : words) {
        result.append(word);
    }

没有用途,因为您在任何地方都不使用result变量。

您的一些评论应该成为JavaDoc,特别是用于描述公共方法:

代码语言:javascript
复制
/**
 * 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() { ... }
票数 5
EN

Code Review用户

发布于 2019-03-06 07:38:17

我想知道专业人士如何评价我的代码

对不起,让你失望了:P,但是也许有一些人认为,在我的脑海中,总有一天会帮助你。本综述是对@Ralf Kleberhoff的补充

也许是

当我跑的时候

代码语言:javascript
复制
public static void main(String[] args) {
    TextConfuser textConfuser = new TextConfuser("Excellent Sir");
    textConfuser.parse();
    textConfuser.confuse();
    System.out.println(textConfuser.getConfusedText());
}

最后一个字消失了。

代码语言:javascript
复制
Elenxeclt 

金刚石算子

与两次指定对象的类型不同,只要编译器能够从上下文中推断类型,就可以指定菱形操作符<>。因此,在实例化对象时可以使用菱形操作符。

在您的代码库中

this.words =新ArrayList() words =新ArrayList();

如果您使用的是Java 7+,那么只需编写new ArrayList<>()即可。

对象创建

同时(!chars.isEmpty()) {随机随机=新随机();// .}

这个while-循环为chars中的每个元素创建了一个新的Random实例。最好是将初始化挂在while循环之上,只初始化一次。

代码语言:javascript
复制
Random random = new Random();
while (!chars.isEmpty()) {
    // ..
}

注释

罗伯特·C·马丁( Robert C. Martin )写了一本书“清洁代码”(Clean),还有更多令人悲伤的书。

当您可以使用函数或变量时,不要使用注释

您的注释做得很好,并将它们分组为逻辑单元,但是我们可以将这些逻辑单元提取到它们自己的方法中。

代码语言:javascript
复制
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);
        }
    }
}

原始痴迷特征Envy & 值对象

原始痴迷是使用原始数据类型来表示领域思想。例如,我们使用字符串来表示消息...。

我们原始的痴迷是word。它来自String类型,我们可以轻松地创建一个新的类Word,它将是一个值对象。

对象的全部意义在于,它们是一种将数据与该数据上使用的进程一起打包的技术。经典的代码气味是一种方法,它似乎更感兴趣的是一个类,而不是它所在的类。

这句话意味着在我们的例子中,TextConfuser更忙于操作一个word来混淆空洞语句。

代码语言:javascript
复制
public void confuse() {
    parse();
    for (Word word : words) {
        Word confused = word.randomizeReadable();
        confusedText.append(confused.get())    
    }
}

randomizeReadable on Word方法具有如何操作字符串的孔逻辑。

票数 2
EN

Code Review用户

发布于 2019-03-06 07:43:48

从本质上讲,这个问题有三个部分:

  1. 分割流到令牌。
  2. (甚至是一个词)象征。
  3. 将令牌写入流。

为了维护单一责任原则,这些部分应该分离成它们自己的类。现在,所有的代码都在一个类和单元测试中,这将是相当困难的。

票数 0
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/214763

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档