项目要求

实现一个统计程序,它能正确统计程序文件中的字符数、单词数、行数,以及还具备其他扩展功能,并能够快速地处理多个文件。
具体功能要求:
程序处理用户需求的模式为:

wc.exe [parameter]
[file_name]

  • 基本功能列表:

    wc.exe -c file.c     //返回文件 file.c 的字符数(实现)

    wc.exe -w file.c    //返回文件 file.c 的词的数目 (实现)

    wc.exe -l file.c      //返回文件 file.c 的行数(实现)

  • 扩展功能:

  -s   递归处理目录下符合条件的文件。(实现)
  -a   返回更复杂的数据(代码行 / 空行 / 注释行)。(实现)

  • 高级功能:

  -x 参数。这个参数单独使用。如果命令行有这个参数,则程序会显示图形界面,用户可以通过界面选取单个文件,程序就会显示文件的字符数、行数等全部统计信息。

  (实现)

  需求举例:
    wc.exe -s -a *.c (实现)

    返回当前目录及子目录中所有*.c
文件的代码行数、空行数、注释行数。


Github项目地址:https://github.com/kvhong/JAVA-to-bulid-wc.exe

 解题思路

主函数思路:通过输入的命令来判断执行各个功能函数,将输入的命令分割为两部分,第一部分是指令,第二部分是文件路径,用指令来调用各个功能函数,文件路径则作为参数输入到各个功能函数中实现功能。

功能函数的共同部分:通过传入的文件路径并用Buffer流读取文件内容,对文件内容进行相应统计然后输出结果,需实现文件不存在或者路径输入错误提示。

词数统计函数:需要去除空行、各种符号,将独立的词统计出来;

字符统计函数:需要去除空行、空格,将其余的内容的每一个单元都示为一个字符统计出来;

行数统计函数:文件中全部行数除结尾空行不算外其他都统计;

空行:TAB、空格、回车形成的空行都算入;

注释行:单独存在//、/*、*/的算入注释行;

代码行:除了空行、注释行外属于代码行;

帮助:将各种命令列出,以更好的帮助使用;

 用户使用说明

-c 文件(须包含文件完整路径) 统计程序文件中的字符数
-w 文件(须包含文件完整路径) 统计程序文件中的单词数
-l 文件(须包含文件完整路径) 统计程序文件中的行数
-a 文件(须包含文件完整路径) 统计程序文件中的空行数、代码行数、注释行数
-s-a 文件路径或者文件夹路径 递归统计程序文件中的空行数、代码行数、注释行数(-s 命令不可单独使用)
? 帮助
end 结束程序

 遇到的问题及解决方法

一开始不知道如何对词、字符进行有效的分割,然后在网上学习到可以用正则表达式进行分割:使用下面语句将数字和和中英文标点符号和中文都替换成空格,以通过空格分割出各个词。

str.replaceAll("[\\p{Nd}\\u9fa5-\\uffe5\\p{Punct}\\s&&[^-]]", " ");

使用下面的正则匹配器匹配注释行和空行

Pattern nodeLinePattern = Pattern.compile("((//)|(/\\*+)|((^\\s)*\\*)|((^\\s)*\\*+/))+",
Pattern.MULTILINE + Pattern.DOTALL); // 注释匹配器(匹配单行、多行、文档注释)
Pattern spaceLinePattern = Pattern.compile("^\\s*$"); // 空白行匹配器(匹配回车、tab键、空格)

设计及代码

该程序通过一个主函数文件和一个方法函数文件组成。主函数文件用于输入参数并判断所输入的各种操作以调用方法函数。方法函数用于实现各种功能:

文件词数统计函数:getwordnumber()  命令:-w  文件路径(须包含完整路径)

//文件词统计函数
int getwordnumber(String filename) throws IOException {int num=0;
String[] strword = null;
File file = new File(filename);
if(file.exists()) {
//读取文件
FileReader fr = new FileReader(filename);
br = new BufferedReader(fr);
String line = null;
StringBuffer sbf = new StringBuffer();
while((line=br.readLine())!= null) {
sbf.append(line);
String str = sbf.toString();
//正则表达式替换符号
str = str.replaceAll("[\\p{Nd}\\u9fa5-\\uffe5\\p{Punct}\\s&&[^-]]", " ");
//按空格将内容分割
strword = str.split("\\s+");
num=strword.length;
}
br.close();
fr.close();
}else {
System.out.println("文件不存在,请重新输入文件!");
}
return num;
}

文件字符数统计函数:getCharacternumber()  命令:-c  文件路径(须包含完整路径)

//文件字符统计函数
int getCharacternumber(String filename) throws IOException {int number = 0;
String[] strword = null;
File file = new File(filename);
if(file.exists()) {
//读取文件
FileReader fr = new FileReader(filename);
br = new BufferedReader(fr);
String line = null;
String str=null;
StringBuffer sbf = new StringBuffer();
while((line=br.readLine())!= null) {
sbf.append(line);
str = sbf.toString();
strword = str.split("\\s+");
}
for(int i=0;i<strword.length;i++) {
Pattern pattern = Pattern.compile("[0-9a-zA-Z]*");
Matcher matcher = pattern.matcher(strword[i]);
if(matcher.find()) {
number+=matcher.regionEnd();
}
}
br.close();
fr.close();
}else {
System.out.println("文件不存在,请重新输入文件!");
}
return number;
}

文件行数统计函数:getlinenumber()  命令:-l  文件路径(须包含完整路径)

//文件行数统计函数
int getlinenumber(String filename) throws IOException {int linenum = 0;
File file = new File(filename);
if(file.exists()) {
//读取文件
FileReader fr = new FileReader(filename);
//读取文件行数
LineNumberReader lnr = new LineNumberReader(fr);
while(lnr.readLine()!= null) {
linenum=lnr.getLineNumber();
}
lnr.close();
fr.close();
}else {
System.out.println("文件不存在,请重新输入文件!");
}
return linenum;
}

统计文件或者文件夹中程序文件的空行、代码行、注释行,有递归文件目录功能的函数,将递归功能一同实现在此函数中:diffline()  命令:-a 文件路径或文件夹路径/-s-a 文件路径或文件夹路径

//统计文件或者文件夹中程序文件的空行、代码行、注释行,有递归文件目录功能
int[] difflineGUI(File file) throws IOException {
int spaceline = 0;
int nodeline = 0;
int codeline = 0;
if (file == null || !file.exists()) {
System.out.println(file + ",文件不存在!");
}else {
if (file.isDirectory()) {
File[] files = file.listFiles(new FileFilter() {
public boolean accept(File pathname) {
return pathname.getName().endsWith(".java")|| pathname.isDirectory()||
pathname.getName().endsWith(".c")||pathname.getName().endsWith(".cpp") ;
}
});
//递归文件目录
for (File target : files) {
diffline(target);
}
} else {
BufferedReader bufr = null;
// 将指定路径的文件与字符流绑定
bufr = new BufferedReader(new InputStreamReader(new FileInputStream(file))); // 定义匹配每一行的正则匹配器
Pattern nodeLinePattern = Pattern.compile("((//)|(/\\*+)|((^\\s)*\\*)|((^\\s)*\\*+/))+",
Pattern.MULTILINE + Pattern.DOTALL); // 注释匹配器(匹配单行、多行、文档注释) Pattern spaceLinePattern = Pattern.compile("^\\s*$"); // 空白行匹配器(匹配回车、tab键、空格) // 遍历文件中的每一行,并根据正则匹配的结果记录每一行匹配的结果
String line = null;
while((line = bufr.readLine()) != null) {
if (nodeLinePattern.matcher(line).find()) {
nodeline ++;
}else if (spaceLinePattern.matcher(line).find()) {
spaceline ++;
}else{
codeline ++;
}
}
}
}
int[] Sline= {spaceline,nodeline,codeline};
return Sline;
}

用于wctest.java文件:

//统计文件或者文件夹中程序文件的空行、代码行、注释行,有递归文件目录功能
void diffline(File file) throws IOException {
int spaceline = 0;
int nodeline = 0;
int codeline = 0;
if (file == null || !file.exists()) {
System.out.println(file + ",文件不存在!");
}else {
if (file.isDirectory()) {
File[] files = file.listFiles(new FileFilter() {
public boolean accept(File pathname) {
return pathname.getName().endsWith(".java")|| pathname.isDirectory()||
pathname.getName().endsWith(".c")||pathname.getName().endsWith(".cpp") ;
}
});
//递归文件目录
for (File target : files) {
diffline(target);
}
} else {
System.out.println("文件名:"+file.getAbsolutePath());
// 将指定路径的文件与字符流绑定
BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
// 定义匹配每一行的正则匹配器
Pattern nodeLinePattern = Pattern.compile("((//)|(/\\*+)|((^\\s)*\\*)|((^\\s)*\\*+/))+",
Pattern.MULTILINE + Pattern.DOTALL); // 注释匹配器(匹配单行、多行、文档注释) Pattern spaceLinePattern = Pattern.compile("^\\s*$"); // 空白行匹配器(匹配回车、tab键、空格) // 遍历文件中的每一行,并根据正则匹配的结果记录每一行匹配的结果
String line = null;
while((line = bufr.readLine()) != null) {
if (nodeLinePattern.matcher(line).find()) {
nodeline ++;
}else if (spaceLinePattern.matcher(line).find()) {
spaceline ++;
}else{
codeline ++;
}
}
System.out.println("空行数:"+spaceline);
System.out.println("注释行数:"+nodeline);
System.out.println("代码行数:"+codeline);
}
}
}

用于wctest.java的统计空行、注释行、代码行函数

帮助函数:help()  命令:?

//帮助函数
void help(){
System.out.println("-c 文件(须包含文件完整路径) 统计程序文件中的字符数");
System.out.println("-w 文件(须包含文件完整路径) 统计程序文件中的单词数");
System.out.println("-l 文件(须包含文件完整路径) 统计程序文件中的行数");
System.out.println("-a 文件(须包含文件完整路径) 统计程序文件中的空行数、代码行数、注释行数");
System.out.println("-s-a 文件路径或者文件夹路径 递归统计程序文件中的空行数、代码行数、注释行数");
System.out.println("-x 打开用户界面");
System.out.println("? 帮助");
System.out.println("end 结束程序");
}

主函数:wctest.java

package wc;

import java.io.File;
import java.io.IOException;
import java.util.Scanner; public class wctest{ private static Scanner scanner; public static void main(String[] args) throws IOException{
String str = null;
wcfunction wcf = new wcfunction();
//循环询问命令输入
while(true) {
System.out.print("请输入命令:");
//命令输入
scanner = new Scanner(System.in);
if(scanner.hasNext()) {
str=scanner.nextLine();
}
//分割命令,第一个作为判断第二个为文件路径
String[] strword = str.split(" ");
if(strword.length==2) {
if(strword[0].equals("-c")) {
int chara=wcf.getCharacternumber(strword[1]);
System.out.println("该文件的字符数:"+chara);
}else if(strword[0].equals("-w")) {
int word=wcf.getwordnumber(strword[1]);
System.out.println("该文件的词数:"+word);
}else if(strword[0].equals("-l")) {
int line=wcf.getlinenumber(strword[1]);
System.out.println("该文件的行数:"+line);
}else if(strword[0].equals("-a")) {
File file = new File(strword[1]);
int[] linenum=wcf.diffline(file);
System.out.println("该文件的空行数:"+linenum[0]);
System.out.println("该文件的注释行数:"+linenum[1]);
System.out.println("该文件的代码行数:"+linenum[2]);
}else if(strword[0].equals("-s-a")) {
File file = new File(strword[1]);
int[] linenum=wcf.diffline(file);
System.out.println("该文件的空行数:"+linenum[0]);
System.out.println("该文件的注释行数:"+linenum[1]);
System.out.println("该文件的代码行数:"+linenum[2]);
}
}else {
if(strword[0].equals("?")) {
wcf.help();
}else if(strword[0].equals("-x")) {
wcGUI.main(null);
}else if(strword[0].equals("end")) {
break;
}else {
System.out.println("命令输入错误,请重新输入!");
}
} }
}
}

用户界面文件:wcGUI.java  命令:-x

package wc;

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import javax.swing.JScrollPane;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JLabel;
import javax.swing.SwingConstants; public class wcGUI { private JFrame frmWc;
private JTextField codenum;
private JTextField wordnum;
private JTextField linenum;
private JTextField spaceline;
private JTextField nodeline;
private JTextField codeline;
File file;
wcfunction wcf=new wcfunction(); /**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
wcGUI window = new wcGUI();
window.frmWc.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
} /**
* Create the application.
*/
public wcGUI() {
initialize();
} /**
* Initialize the contents of the frame.
*/
private void initialize() {
frmWc = new JFrame();
frmWc.setTitle("wc");
frmWc.setResizable(false);
frmWc.setBounds(280, 50, 800, 600);
frmWc.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); JPanel panel = new JPanel();
frmWc.getContentPane().add(panel, BorderLayout.CENTER);
panel.setLayout(null); JScrollPane scrollPane = new JScrollPane();
scrollPane.setBounds(291, 0, 493, 562);
panel.add(scrollPane); JPanel panel_1 = new JPanel();
scrollPane.setViewportView(panel_1);
panel_1.setLayout(new BorderLayout(0, 0)); JTextArea textArea = new JTextArea();
textArea.setEditable(false);
panel_1.add(textArea, BorderLayout.CENTER); JButton choosefile = new JButton("选择文件");
choosefile.setBounds(10, 32, 122, 23);
panel.add(choosefile); JLabel filename = new JLabel("文件名:");
filename.setBounds(10,70,80,23);
panel.add(filename); JTextArea filepath = new JTextArea();
filepath.setBounds(10, 95, 260, 40);
filepath.setLineWrap(true);
filepath.setWrapStyleWord(true);
filepath.setEditable(false);
panel.add(filepath); JButton code = new JButton("统计字符数");
code.setBounds(10, 277, 100, 30);
panel.add(code); JButton word = new JButton("统计词数");
word.setBounds(10, 317, 93, 30);
panel.add(word); JButton line = new JButton("统计行数");
line.setBounds(10, 357, 93, 30);
panel.add(line); JButton diffline = new JButton("统计空行、注释行、代码行");
diffline.setBounds(10, 397, 224, 30);
panel.add(diffline); codenum = new JTextField();
codenum.setBounds(120, 278, 93, 29);
codenum.setEditable(false);
panel.add(codenum);
codenum.setColumns(10); wordnum = new JTextField();
wordnum.setBounds(113, 318, 93, 30);
wordnum.setEditable(false);
panel.add(wordnum);
wordnum.setColumns(10); linenum = new JTextField();
linenum.setColumns(10);
linenum.setBounds(113, 358, 93, 30);
linenum.setEditable(false);
panel.add(linenum); spaceline = new JTextField();
spaceline.setColumns(10);
spaceline.setBounds(70, 437, 93, 29);
spaceline.setEditable(false);
panel.add(spaceline); nodeline = new JTextField();
nodeline.setColumns(10);
nodeline.setBounds(70, 476, 93, 29);
nodeline.setEditable(false);
panel.add(nodeline); codeline = new JTextField();
codeline.setColumns(10);
codeline.setBounds(70, 515, 93, 30);
codeline.setEditable(false);
panel.add(codeline); JLabel label = new JLabel("空行");
label.setHorizontalAlignment(SwingConstants.CENTER);
label.setBounds(10, 437, 54, 29);
panel.add(label); JLabel label_1 = new JLabel("注释行");
label_1.setHorizontalAlignment(SwingConstants.CENTER);
label_1.setBounds(10, 476, 54, 29);
panel.add(label_1); JLabel label_2 = new JLabel("代码行");
label_2.setHorizontalAlignment(SwingConstants.CENTER);
label_2.setBounds(10, 515, 54, 30);
panel.add(label_2); JLabel label_3 = new JLabel("个");
label_3.setBounds(216, 277, 54, 30);
panel.add(label_3); JLabel label_4 = new JLabel("个");
label_4.setBounds(216, 317, 54, 30);
panel.add(label_4); JLabel label_5 = new JLabel("行");
label_5.setBounds(216, 357, 54, 30);
panel.add(label_5); JLabel label_6 = new JLabel("行");
label_6.setBounds(173, 437, 54, 30);
panel.add(label_6); JLabel label_7 = new JLabel("行");
label_7.setBounds(173, 476, 54, 30);
panel.add(label_7); JLabel label_8 = new JLabel("行");
label_8.setBounds(173, 515, 54, 30);
panel.add(label_8); choosefile.addActionListener(new ActionListener() { @Override
public void actionPerformed(ActionEvent e) {
JFileChooser filechooser = new JFileChooser(".");
int result=filechooser.showOpenDialog(null);
if(result == JFileChooser.APPROVE_OPTION){
file=filechooser.getSelectedFile();
if(file!=null) {
if(textArea.getText()!=null) {
textArea.setText("");
}
if(filepath.getText()!=null) {
filepath.setText("");
filepath.setText(file.getPath());
}
try {
InputStreamReader read = new InputStreamReader(new FileInputStream(file), "GB2312");
BufferedReader br = new BufferedReader(read);
String line=null;
while((line=br.readLine())!=null) {
textArea.append(line+"\r\n");
}
br.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}); code.addActionListener(new ActionListener() { @Override
public void actionPerformed(ActionEvent e) {
if(file.exists()) {
String filename = file.getAbsolutePath();
try {
int chara=wcf.getCharacternumber(filename);
codenum.setText(chara+"");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} } }
}); word.addActionListener(new ActionListener() { @Override
public void actionPerformed(ActionEvent e) {
if(file.exists()) {
String filename = file.getAbsolutePath();
try {
int word=wcf.getwordnumber(filename);
wordnum.setText(word+"");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} } }
}); line.addActionListener(new ActionListener() { @Override
public void actionPerformed(ActionEvent e) {
if(file.exists()) {
String filename = file.getAbsolutePath();
try {
int line=wcf.getlinenumber(filename);
linenum.setText(line+"");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} } }
}); diffline.addActionListener(new ActionListener() { @Override
public void actionPerformed(ActionEvent e) {
if(file.exists()) {
try {
int[] line=wcf.difflineGUI(file);
spaceline.setText(line[0]+"");
nodeline.setText(line[1]+"");
codeline.setText(line[2]+"");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} } }
});
}
}

用户界面wcGUI.java

测试

已将程序打包成wc.exe文件,放在Github项目中。可直接打开exe文件输入命令和文件路径直接使用,也可使用CMD命令行运行wc.exe再输入命令和文件路径使用。

CMD命令行使用:

exe直接使用:

用户界面:

代码覆盖率

代码覆盖率:97.5%

PSP

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 45 60
· Estimate · 估计这个任务需要多少时间 45 60
Development 开发 1290 1540
· Analysis · 需求分析 (包括学习新技术) 80 120
· Design Spec · 生成设计文档 40 60
· Design Review · 设计复审 (和同事审核设计文档) 40 40
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 30 30
· Design · 具体设计 120 160
· Coding · 具体编码 780 920
· Code Review · 代码复审 80 90
· Test · 测试(自我测试,修改代码,提交修改) 120 120
Reporting 报告 240 380
· Test Report · 测试报告 120 220
· Size Measurement · 计算工作量 30 40
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 90 120
  合计 1575 1980

总结

先是从课堂上更加意识到制定设计流程的重要性,了解到计划的设计不仅仅只存在于流程,对时间的规划也是非常重要的。在编写代码过程中实质遇到的困难是在如何实现词数的统计、正则表达式以及对文件目录的递归实现。最后通过学习正则表达式实现了对词数的统计,也进一步学习了正则表达式这一较为陌生的概念。也学会了一些新的插件和软件的使用:Eclipse的EclEmma插件用于代码覆盖率的统计;Git Bash软件对本地项目上传到Github使用;exe4j软件对JAVA项目进行EXE文件的打包使用。这次的项目作业对我来说是受益匪浅,对以后的项目实行有很大的帮助。

JAVA实现WC.exe功能的更多相关文章

  1. 小白のjava实现wc.exe功能

    GitHub地址 项目完成情况 基本功能列表(已实现) wc.exe -c file.c     //返回文件 file.c 的字符数 wc.exe -w file.c    //返回文件 file. ...

  2. 软件工程:Java实现WC.exe基本功能

    项目相关要求 GitHub地址:https://github.com/3216004716/WC 实现一个统计程序,它能正确统计程序文件中的字符数.单词数.行数,以及还具备其他扩展功能,并能够快速地处 ...

  3. 用c语言基本实现wc.exe功能

    网址:https://github.com/3216005214/wc.exe wc项目要求 wc.exe 是一个常见的工具,它能统计文本文件的字符数.单词数和行数.这个项目要求写一个命令行程序,模仿 ...

  4. java实现wc.exe

    Github地址:https://github.com/ztz1998/wc/tree/master 项目相关要求 实现一个统计程序,它能正确统计程序文件中的字符数.单词数.行数,以及还具备其他扩展功 ...

  5. 软工作业No.1。Java实现WC.exe

    网址:https://github.com/a249970271/WC WC 项目要求 wc.exe 是一个常见的工具,它能统计文本文件的字符数.单词数和行数.这个项目要求写一个命令行程序,模仿已有w ...

  6. Java 实现 WC.exe

    Github:https://github.com/YJOED/Code/tree/master/WC/src 一.题目:实现一个统计程序,它能正确统计程序文件中的字符数.单词数.行数,以及还具备其他 ...

  7. Java实现WC基本功能

    GitHub仓库:https://github.com/douyazai/WCbase 一.WC 项目要求 wc.exe 是一个常见的工具,它能统计文本文件的字符数.单词数和行数.这个项目要求写一个命 ...

  8. 软工作业1—java实现wc.exe

    github项目地址 https://github.com/liyizhu/wc.exe WC 项目要求 基本功能列表: wc.exe -c file.c     //返回文件 file.c 的字符数 ...

  9. Java实现wc部分功能

    GitHub仓库:https://github.com/TaoTaoLv1/WcProject 一.开发前PSP表格预估* PSP2.1 Personal Software Process Stage ...

随机推荐

  1. 数据类型-DataFrame

    数据类型-DataFrame DataFrame是由多个Series数据列组成的表格数据类型,每行Series值都增加了一个共用的索引 既有行索引,又有列索引 行索引,表明不同行,横向索引,叫inde ...

  2. tflearn 实现DNN 全连接

    https://github.com/tflearn/tflearn/blob/master/examples/others/recommender_wide_and_deep.py import n ...

  3. Mysql修改密码办法

    方法1: 用SET PASSWORD命令 首先登录MySQL. 格式:mysql> set password for 用户名@localhost = password('新密码'); 例子:my ...

  4. MySql的基本架构续

    [数据拆分后引入的问题] 数据水平拆分引入的问题主要是只能通过sharding key来读写操作,例如以userid为sharding key的切分例子,读userid的详细信息时,一定需要先知道us ...

  5. 36. Valid Sudoku (Array; HashTable)

    Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. The Sudoku board could be ...

  6. AIDL--------应用之间的通信接口

    在下面例子中04Service中添加aidl包包里定义好接口 接口文件名后缀为.aidl package com.example.aidl; interface IRemoteService{ voi ...

  7. Developing ADF PageTemplates

    Developing ADF PageTemplates In this hands-on, you learn how to create a page template and use this ...

  8. 调用父类构造器:super

    import static java.lang.System.*; class Base{ public String name; public double weight; public Base( ...

  9. Codeforces 709C 模拟

    C. Letters Cyclic Shift time limit per test:1 second memory limit per test:256 megabytes input:stand ...

  10. 如何看待阿里 AI 每秒制作 8000 张海报?

    看了其他设计老师们的回答,给了我一些启发,于是更新一波. 设计本质上是产品和服务的一部分,如果只站在设计师角度看这问题,免不了会有一种被取代的危机感. 来源:千锋UI ​但如果站在整个产品和服务的角度 ...