先看效果:截圖1java
截圖2:git
實現思路:github
一、界面UI設計算法
二、功能點 : a 打開文件進行比較 b 粘貼內容進去比較 c 提示幫助 d 窗口能夠任意拖動數組
三、文本比較算法app
java類 :ide
MainUI 類實現界面設計 Read_File 類實現文件讀取 DNASequence 類文本比較算法佈局
項目結構:字體
源代碼:this
Star.java
import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; public class Star { public static void main(String args[]) throws BadLocationException { //初始化界面 Windowm windowm = new Windowm(); //屬性設置 SimpleAttributeSet attrset = new SimpleAttributeSet(); //字體大小 StyleConstants.setFontSize(attrset,16); //獲取JTextPane對象 Document docs1=windowm.text1.getDocument(); //設置初次顯示文本 docs1.insertString(docs1.getLength(), "手動輸入或者選擇文件打開", attrset); Document docs2=windowm.text2.getDocument(); docs2.insertString(docs2.getLength(), "手動輸入輸入或者選擇文間打開\n點擊覈對試試\n紅色表示錯誤字符\n藍色表示多餘或缺失字符", attrset); } }
MainUI.java
import algorithm.DNASequence; import open_file.Read_File; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import javax.swing.*; import javax.swing.text.Document; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; class Windowm extends JFrame { String path1;//第一個文件目錄 String path2;//第二個文件目錄 String File1;//第一個文件 String File2;//第二個文件 int point;//保存當前活動窗口 private static final long serialVersionUID = 1L; JPanel myPanel1 = new JPanel();//面板1.1 JPanel myPanel2 =new JPanel();//面板2.1 JPanel myPanel3 =new JPanel();//面板3 JPanel myPanel4 =new JPanel();//面板4 JTextPane text1=new JTextPane(); JTextPane text2=new JTextPane(); JButton bt1 = new JButton("打開文檔1"); JButton bt2 = new JButton("打開文檔2"); JButton bt3 = new JButton("覈對"); JPopupMenu jm = new JPopupMenu();//右鍵菜單 JMenuItem copy = new JMenuItem("複製");//菜單項 JMenuItem path = new JMenuItem("粘貼"); JMenuItem cut = new JMenuItem("剪切"); JMenuItem help = new JMenuItem("幫助"); JMenuItem about = new JMenuItem("關於"); JScrollPane scro1=new JScrollPane(text1);//添加滾動條 JScrollPane scro2=new JScrollPane(text2);//添加滾動條 JSplitPane jSplitPane =new JSplitPane();//設定爲拆分佈局 JSplitPane jSplitPane2 =new JSplitPane();//設定爲拆分佈局 JSplitPane jSplitPane3 =new JSplitPane();//設定爲拆分佈局 public Windowm() { setVisible(true); jm.add(copy); jm.add(path); jm.add(cut); jm.add(help); jm.add(about); myPanel3.add(bt1); myPanel3.add(bt2); myPanel4.add(bt3); this.setTitle("歡迎使用文本比較軟件"); this.setBounds(100, 100, 600, 500); jSplitPane.setContinuousLayout(true);//操做箭頭,重繪圖形 jSplitPane2.setContinuousLayout(true);//操做箭頭,重繪圖形 jSplitPane3.setContinuousLayout(true);//操做箭頭,重繪圖形 jSplitPane2.setOrientation(JSplitPane.VERTICAL_SPLIT);//垂直方向 jSplitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT);//水平方向 jSplitPane3.setOrientation(JSplitPane.VERTICAL_SPLIT);//垂直方向 myPanel1.setBorder(BorderFactory.createLineBorder(Color.green)); myPanel2.setBorder(BorderFactory.createLineBorder(Color.red)); myPanel3.setBorder(BorderFactory.createLineBorder(Color.yellow)); myPanel4.setBorder(BorderFactory.createLineBorder(Color.blue)); jSplitPane.setLeftComponent(scro1);//左右佈局中添加組件 ,面板1 jSplitPane.setRightComponent(scro2);//左右佈局中添加組件 ,面板2 jSplitPane2.setTopComponent(myPanel3);//上下佈局中添加組件 ,面板1 jSplitPane2.setBottomComponent(jSplitPane);//上下佈局中添加組件 ,面板1 jSplitPane3.setTopComponent(jSplitPane2); jSplitPane3.setBottomComponent(myPanel4); jSplitPane.setDividerSize(5);//設置分割線的寬度 jSplitPane2.setDividerSize(5);//設置分割線的寬度 jSplitPane3.setDividerSize(5);//設置分割線的寬度 setContentPane(jSplitPane3);//設置爲父模塊 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); copy.addActionListener(new ActionListener()//窗口監聽 { public void actionPerformed(ActionEvent e4)//菜單項 { try{ text1.copy(); text2.copy(); }catch(Exception e1){ } } } ); path.addActionListener(new ActionListener()//窗口監聽 { public void actionPerformed(ActionEvent e4)//菜單項 { try{ if(point==1)//因爲有兩個窗口,所以設計point來肯定粘貼在某個窗口 text1.paste(); else text2.paste(); }catch(Exception e1){ } } } ); cut.addActionListener(new ActionListener()//窗口監聽 { public void actionPerformed(ActionEvent e4)//菜單項 { try{ text1.cut(); text2.cut(); }catch(Exception e1){ } } } ); help.addActionListener(new ActionListener()//窗口監聽 { public void actionPerformed(ActionEvent e4)//菜單項 { JOptionPane.showMessageDialog(null,"使用方法:輸入或者點擊打開兩個文本,按覈對鍵進行比較\n紅色表示匹配失敗,藍色表示多餘,黑色爲正常匹配文本","使用指南",JOptionPane.PLAIN_MESSAGE); } } ); about.addActionListener(new ActionListener()//窗口監聽 { public void actionPerformed(ActionEvent e4)//菜單項 { JOptionPane.showMessageDialog(null,"原創:將軍\nQQ 2910001378@qq.com \n人生苦短,歡迎轉載","將軍原創",JOptionPane.PLAIN_MESSAGE); } } ); text1.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON3) { jm.show(text1, e.getX(), e.getY()); // 彈出菜單 point=1; } } }); text2.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON3) { jm.show(text2, e.getX(), e.getY()); // 彈出菜單 point=2; } } }); jSplitPane.addComponentListener(new ComponentAdapter() {//拖動窗口監聽 public void componentResized(ComponentEvent e) { jSplitPane.setDividerLocation(jSplitPane3.getWidth()/2-7);//設置第一條寬度 } }); jSplitPane2.setDividerLocation(50);//設定分割線的距離左邊的位置 jSplitPane3.addComponentListener(new ComponentAdapter() {//拖動窗口監聽 public void componentResized(ComponentEvent e) { jSplitPane3.setDividerLocation(jSplitPane3.getHeight()-50);//設置第三條高度 } }); bt1.addActionListener(new ActionListener()//窗口監聽 { public void actionPerformed(ActionEvent e4)//菜單項 { try{ text1.setText(""); JFileChooser jfc=new JFileChooser(); jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES ); jfc.showDialog(new JLabel(), "選擇"); File file=jfc.getSelectedFile(); path1=file.getAbsolutePath();//獲取文件絕對地址 new Read_File(path1); File1= Read_File.getFile(); SimpleAttributeSet attrset = new SimpleAttributeSet(); StyleConstants.setFontSize(attrset,16);//設置字號 Document docs=text1.getDocument(); docs.insertString(docs.getLength(), File1, attrset); }catch(Exception e1){ } } } ); bt2.addActionListener(new ActionListener()//窗口監聽 { public void actionPerformed(ActionEvent e4)//菜單項 { try{ text2.setText(""); JFileChooser jfc=new JFileChooser(); jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES ); jfc.showDialog(new JLabel(), "選擇"); File file=jfc.getSelectedFile(); path2=file.getAbsolutePath();//獲取文件絕對地址 new Read_File(path2); File2= Read_File.getFile(); SimpleAttributeSet attrset = new SimpleAttributeSet(); StyleConstants.setFontSize(attrset,16);//設置字號 Document docs=text2.getDocument(); docs.insertString(docs.getLength(), File2, attrset); }catch(Exception e1){ System.out.println("選擇文件出錯"); } } } ); bt3.addActionListener(new ActionListener()//窗口監聽 { public void actionPerformed(ActionEvent e4)//菜單項 { try{ String dnas1;//算法處理以後的字符串1 String dnas2;//算法處理以後的字符串2 String jtp1;//JTextpane的內容1 String jtp2;//JTextpane的內容2 int len=0; //處理後的字符串長度 jtp1=text1.getText();//獲取窗口文本 jtp2=text2.getText(); text1.setText("");//清空以前內容 text2.setText(""); Document docs1=text1.getDocument(); Document docs2=text2.getDocument(); DNASequence dna=new DNASequence(jtp1,jtp2);//經過構造方法傳遞參數 dna.runAnalysis(); dna.traceback(); dnas1=dna.getString1();//獲取處理後的字符串 dnas2=dna.getString2(); char[] s = dnas1.toCharArray();//字符串轉Char數組 char[] p = dnas2.toCharArray(); len=dnas1.length(); SimpleAttributeSet set2 = new SimpleAttributeSet();//設置一個屬性 StyleConstants.setFontSize(set2,16);//設置字號 for(int i=0;i<len;i++){ if(s[i]=='-'){ StyleConstants.setForeground(set2,Color.BLUE);//設置文字顏色 docs2.insertString(docs2.getLength(),String.valueOf(p[i]), set2); }else if(p[i]=='-'){ StyleConstants.setForeground(set2,Color.BLUE);//設置文字顏色 docs1.insertString(docs1.getLength(),String.valueOf(s[i]), set2); }else if(s[i]==p[i]){ StyleConstants.setForeground(set2,Color.black);//設置文字顏色 docs1.insertString(docs1.getLength(),String.valueOf(s[i]), set2); docs2.insertString(docs2.getLength(),String.valueOf(p[i]), set2); }else if(s[i]!=p[i]){ StyleConstants.setForeground(set2,Color.red);//設置文字顏色 docs1.insertString(docs1.getLength(),String.valueOf(s[i]), set2); docs2.insertString(docs2.getLength(),String.valueOf(p[i]), set2); }else{ System.out.print("考慮更多顏色"); } } }catch(Exception e1){ System.out.println("選擇文件2出錯"); } } } ); } }
Read_File.java
import java.io.BufferedReader; import java.io.FileInputStream; import java.io.InputStreamReader; public class Read_File { static String fileName; public Read_File(String str){ fileName=str; } public static String getFile(){ BufferedReader br = null; StringBuffer sb = null; try { br = new BufferedReader(new InputStreamReader(new FileInputStream(fileName),"utf-8")); //這裏能夠控制編碼 sb = new StringBuffer(); String line = null; while((line = br.readLine()) != null) { sb.append(line); } } catch (Exception e) { e.printStackTrace(); } finally { try { br.close(); } catch (Exception e) { e.printStackTrace(); } } String data = new String(sb); //StringBuffer ==> String System.out.println("數據爲==> " + data); return data; } // public static void main(String[] args) { // new Read_File("1"); // } }
DNASequence.java
//https://codereview.stackexchange.com/questions/182601/optimizing-needleman-wunsch-algorithm-in-java public class DNASequence { protected final String seq_1, seq_2; //要分析的兩個序列 public int alignmentScore; //使用Needleman-Wunsch算法 protected Node[][] matrix; //存儲分數和縮進 protected final int matchScore, mismatchScore, indel; //用於打印DNA序列分析的字符串 String top = ""; // Sequence 1 String bottom = ""; // Sequence 2 public DNASequence(String s1, String s2) { //我使用一個■做爲緩衝,這樣序列字符串正確對齊 // 在矩陣中使用縮進和分數。 ScoreScheme s = new ScoreScheme(2, -1, -2); seq_1 = "\u25A0" + s1; seq_2 = "\u25A0" + s2; matchScore = s.matchScore; mismatchScore = s.mismatchScore; indel = s.indel; matrix = new Node[seq_1.length()][seq_2.length()]; for (int i = 0; i < seq_1.length(); i++) matrix[i][0] = new Node(i * indel, i, 0); for (int i = 0; i < seq_2.length(); i++) matrix[0][i] = new Node(i * indel, 0, i); } //輔助方法,幫助決定使用哪一種匹配/不匹配得分。 protected int score(int i, int j) { if (seq_1.charAt(i) == seq_2.charAt(j)) return matchScore; else return mismatchScore; } //在本地級別上實現Needleman-Wunsch algo的Helper方法。 protected Node match(int i, int j) { Node s1,s2,s3; s1 = new Node(matrix[i-1][j-1].score + score(i, j), i, j); s2 = new Node(matrix[i-1][j].score + indel, i, j); s3 = new Node(matrix[i][j-1].score + indel, i, j); Node largest = new Node(Math.max(s1.score, Math.max(s2.score, s3.score)), i, j); if (s1.compareTo(largest) == 0) largest.prev = matrix[i-1][j-1]; else if(s2.compareTo(largest) == 0) largest.prev = matrix[i-1][j]; else largest.prev = matrix[i][j-1]; return largest; } public Node runAnalysis() { for (int i = 1; i < seq_1.length(); i++) { for (int j = 1; j < seq_2.length(); j++){ matrix[i][j] = match(i, j); } } alignmentScore = matrix[seq_1.length()-1][seq_2.length()-1].score; return matrix[seq_1.length()-1][seq_2.length()-1]; } //輔助方法,逐步構建分析結果。它將返回 //「尾巴」,由於咱們可能還須要作一些工做。 protected Node traceHelper(Node curr) { while (curr.prev != null) { if (curr.i - curr.prev.i == 1 && curr.j - curr.prev.j == 1){ // If the path leads diagonal boolean x = seq_1.charAt(curr.i) == seq_2.charAt(curr.j) ? true : false; if(x){ top = seq_1.charAt(curr.i) +top; bottom = seq_2.charAt(curr.j) +bottom; }else{ top = seq_1.charAt(curr.i) + top; bottom = seq_2.charAt(curr.j) + bottom; } }else if (curr.i - curr.prev.i == 1){ //若是這條路通向山頂 top = seq_1.charAt(curr.i) + top; bottom = "-" + bottom; //若是這條路通向左邊 }else if (curr.j - curr.prev.j == 1){ top = "-" + top; bottom = seq_2.charAt(curr.j) + bottom; } curr = curr.prev; } return curr; } //從矩陣的最後一個節點回溯到第一個索引節點。 public void traceback() { Node curr = matrix[seq_1.length()-1][seq_2.length()-1]; curr = traceHelper(curr); while (curr.i != 0 || curr.j != 0) { if (curr.i != 0 && curr.j == 0){ curr.prev = matrix[curr.i-1][curr.j]; curr = traceHelper(curr); }else if (curr.i == 0 && curr.j != 0) { curr.prev = matrix[curr.i][curr.j-1]; curr = traceHelper(curr); } } //打印DNA序列分析 // System.out.println(top); // System.out.println(bottom); } public String getString1(){ return top; } public String getString2(){ return bottom; } } class Node implements Comparable<Node>{ int i, j; int score; Node prev; public Node(int score, int x, int y) { this.i = x; this.j = y; this.score = score; this.prev = null; } public int compareTo(Node n) { return this.score - n.score; } public String toString() { return ""+score; } } class ScoreScheme { int matchScore, mismatchScore, indel; public ScoreScheme(int m1, int m2, int i) { matchScore = m1; mismatchScore = m2; indel = i; } }
項目源代碼已經上傳到個人GitHub倉庫 下載點擊https://github.com/Wo-com/TextCheck