├── .gitignore ├── src └── main │ └── java │ └── ucas │ └── gii │ └── parseDrawer │ ├── Example.java │ ├── ParseTreeDrawer.java │ └── VisualTree.java ├── pom.xml ├── TreeDrawer.iml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | .project 3 | .idea 4 | .settings 5 | .classpath 6 | .all -------------------------------------------------------------------------------- /src/main/java/ucas/gii/parseDrawer/Example.java: -------------------------------------------------------------------------------- 1 | package ucas.gii.parseDrawer; 2 | 3 | import java.io.IOException; 4 | import java.util.List; 5 | import java.util.Properties; 6 | 7 | import edu.stanford.nlp.ling.CoreAnnotations.SentencesAnnotation; 8 | import edu.stanford.nlp.pipeline.Annotation; 9 | import edu.stanford.nlp.pipeline.StanfordCoreNLP; 10 | import edu.stanford.nlp.semgraph.SemanticGraphCoreAnnotations.CollapsedCCProcessedDependenciesAnnotation; 11 | import edu.stanford.nlp.trees.TreeCoreAnnotations; 12 | import edu.stanford.nlp.util.CoreMap; 13 | /** 14 | * @Description 15 | * easy example for telling user how to draw a StanfordTree 16 | * @author gii 17 | * @date 2017年4月15日 18 | */ 19 | public class Example { 20 | public static void main(String[] args) throws IOException { 21 | Properties props = new Properties(); 22 | props.put("annotators", "tokenize, ssplit, parse"); 23 | StanfordCoreNLP coreNlp = new StanfordCoreNLP(props); 24 | 25 | String str = "It is a example,you can use the tool like that. Thanks!"; 26 | Annotation document = new Annotation(str); 27 | coreNlp.annotate(document); 28 | List sentences = document.get(SentencesAnnotation.class); 29 | // 上面部分是Stanford CoreNlp的操作过程 30 | // the part above is the operation in Stanford CoreNlp 31 | 32 | ParseTreeDrawer drawer = new ParseTreeDrawer(); 33 | for (CoreMap sentence : sentences) { 34 | drawer.draw(sentence.get(TreeCoreAnnotations.TreeAnnotation.class)); 35 | drawer.draw(sentence.get(CollapsedCCProcessedDependenciesAnnotation.class)); 36 | } 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | ucas.gii 6 | TreeDrawer 7 | 0.0.1-SNAPSHOT 8 | jar 9 | 10 | TreeDrawer 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | 19 | 20 | com.google.guava 21 | guava 22 | 21.0 23 | 24 | 25 | 26 | edu.stanford.nlp 27 | stanford-corenlp 28 | 3.6.0 29 | 30 | 31 | 32 | edu.stanford.nlp 33 | stanford-corenlp 34 | 3.6.0 35 | models 36 | 37 | 38 | 39 | 40 | org.projectlombok 41 | lombok 42 | 1.16.16 43 | 44 | 45 | 46 | junit 47 | junit 48 | 3.8.1 49 | test 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /TreeDrawer.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/main/java/ucas/gii/parseDrawer/ParseTreeDrawer.java: -------------------------------------------------------------------------------- 1 | package ucas.gii.parseDrawer; 2 | 3 | import java.io.File; 4 | import java.io.FileWriter; 5 | import java.io.IOException; 6 | import java.io.PrintWriter; 7 | 8 | import edu.stanford.nlp.semgraph.SemanticGraph; 9 | import edu.stanford.nlp.trees.Tree; 10 | import lombok.Setter; 11 | 12 | /** 13 | * @Description 提供绘画树的接口,主要依赖VisualTree结构 可将结果输出至文件或控制台 14 | * @author gii 15 | * @date 2017年4月16日 16 | */ 17 | public class ParseTreeDrawer { 18 | 19 | private PrintWriter pw; 20 | @Setter 21 | private boolean toConsole; 22 | 23 | /** 24 | * @Description 默认输出至控制台 25 | */ 26 | public ParseTreeDrawer() { 27 | this(true, null); 28 | } 29 | 30 | /** 31 | * @Description 输出至制定文件 32 | * @param file 33 | * @param toConsole 34 | * @throws IOException 35 | */ 36 | public ParseTreeDrawer(File file, boolean toConsole) throws IOException { 37 | this(toConsole, new PrintWriter(new FileWriter(file))); 38 | } 39 | 40 | /** 41 | * 关闭输出流 42 | * 43 | * @Description 44 | */ 45 | public void close() { 46 | if (pw != null) { 47 | pw.close(); 48 | } 49 | } 50 | 51 | public void draw(Tree tree) throws IOException { 52 | if (!this.toConsole && this.pw == null) { 53 | throw new IOException("No place to draw"); 54 | } 55 | draw(this.pw, new VisualTree(tree)); 56 | } 57 | 58 | public void draw(SemanticGraph tree) throws IOException { 59 | if (!this.toConsole && this.pw == null) { 60 | throw new IOException("No place to draw"); 61 | } 62 | draw(this.pw, new VisualTree(tree)); 63 | } 64 | 65 | public void draw(Tree tree, File file) throws IOException { 66 | draw(new PrintWriter(new FileWriter(file)), new VisualTree(tree)); 67 | } 68 | 69 | public void draw(SemanticGraph tree, File file) throws IOException { 70 | draw(new PrintWriter(new FileWriter(file)), new VisualTree(tree)); 71 | } 72 | 73 | public String getTreeContent(SemanticGraph tree) { 74 | return new VisualTree(tree).getVisualContent(); 75 | } 76 | 77 | public String getTreeContent(Tree tree) { 78 | return new VisualTree(tree).getVisualContent(); 79 | } 80 | 81 | private ParseTreeDrawer(boolean toConsole, PrintWriter pw) { 82 | this.pw = pw; 83 | this.toConsole = toConsole; 84 | } 85 | 86 | private void draw(PrintWriter pw, VisualTree vTree) { 87 | 88 | String toOutput = vTree.getVisualContent(); 89 | if (pw != null) { 90 | pw.println(toOutput); 91 | pw.flush(); 92 | } 93 | if (toConsole) { 94 | System.out.println(toOutput); 95 | } 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tree Drawer For StanfordCoreNLP 2 | A small tool to draw a only-text tree as the result of stanford coreNLP. 3 | Welcome to use! 4 | 5 | See Example.java to use. 6 | 7 | ## The tree we get like this: 8 | 9 | 10 | ROOT 11 | | 12 | S 13 | ╭╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶┬╶╶╶╶╶╶┬╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶┬╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╮ 14 | S , NP VP . 15 | ╭╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╮ | | ╭╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╮ | 16 | NP VP , PRP MD VP . 17 | | ╭╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╮ | | ╭╶╶╶╶╶╶╶╶╶╶╶┬╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╮ 18 | PRP VBZ NP you can VB NP PP 19 | | | ╭╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╮ | ╭╶╶╶╶╶╶╶╮ ╭╶╶╶╶╶╶╶╮ 20 | It is NP PP use DT NN IN NP 21 | ╭╶╶╶╶╶╶╶╶╮ ╭╶╶╶╶╶╶╶╶╶╮ | | | | 22 | DT NNS IN NP the tool like DT 23 | | | | | | 24 | a sentences for NN that 25 | | 26 | example 27 | 28 | 29 | 30 | use/VB 31 | ╭╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶┬╶╶╶╶╶╶╶╶┬╶╶╶╶╶╶╶╶╶╶┬╶╶╶╶╶╶╶╶╶╶╶┬╶╶╶╶╶╶╶╶╶╶╶┬╶╶╶╶╶╶╶╶╶╮ 32 | ccomp punct nsubj aux dobj nmod:like punct 33 | | | | | | | | 34 | sentences/NNS ,/, you/PRP can/MD tool/NN that/DT ./. 35 | ╭╶╶╶╶╶╶╶╶╶╶┬╶╶╶╶╶╶╶╶╶┬╶╶╶╶╶╶╶╶╶╮ | | 36 | nsubj cop det nmod:for det case 37 | | | | | | | 38 | It/PRP is/VBZ a/DT example/NN the/DT like/IN 39 | | 40 | case 41 | | 42 | for/IN 43 | 44 | 45 | 46 | ROOT 47 | | 48 | NP 49 | ╭╶╶╶╶╶╶╶╮ 50 | NNS . 51 | | | 52 | Thanks ! 53 | 54 | 55 | 56 | Thanks/NNS 57 | | 58 | punct 59 | | 60 | !/. 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/main/java/ucas/gii/parseDrawer/VisualTree.java: -------------------------------------------------------------------------------- 1 | package ucas.gii.parseDrawer; 2 | 3 | import java.util.List; 4 | import java.util.Queue; 5 | 6 | import com.google.common.collect.Lists; 7 | 8 | import edu.stanford.nlp.ling.IndexedWord; 9 | import edu.stanford.nlp.semgraph.SemanticGraph; 10 | import edu.stanford.nlp.trees.Tree; 11 | import lombok.AllArgsConstructor; 12 | import lombok.Getter; 13 | import lombok.Setter; 14 | 15 | /** 16 | * @Description 输出各类树的数据结构 将各类树结构转化为VisualTree,便于输出 17 | * @author gii 18 | * @date 2017年4月16日 19 | */ 20 | @AllArgsConstructor 21 | public class VisualTree { 22 | private static final char _SPACE = ' '; 23 | private static final char _LINE = (char) 9590; 24 | private static final char LEFT_BAR = (char) 9581; 25 | private static final char RIGHT_BAR = (char) 9582; 26 | private static final char SINGLE_BAR = '|'; 27 | private static final char CONTINUED_BAR = (char) 9516; 28 | private static final int SPACE_LEN = 2; 29 | 30 | private int left; 31 | @Getter 32 | private VisualTree children[]; 33 | @Setter 34 | @Getter 35 | private String content; 36 | private String label; 37 | 38 | public VisualTree(Tree tree) { 39 | this(tree, 0); 40 | } 41 | 42 | public VisualTree(SemanticGraph tree) { 43 | this(tree.getFirstRoot(), tree, 0); 44 | } 45 | 46 | public String getVisualContent() { 47 | int levelLen = 1; 48 | int levelCount = 0; 49 | int childCount = 0; 50 | StringBuffer sb = new StringBuffer(); 51 | StringBuffer lineSb = new StringBuffer(); 52 | StringBuffer allSb = new StringBuffer(); 53 | Queue toOperate = Lists.newLinkedList(); 54 | toOperate.offer(this); 55 | allSb.append(this.content + "\r\n"); 56 | while (toOperate.size() > 0) { 57 | VisualTree op = toOperate.poll(); 58 | VisualTree[] children = op.getChildren(); 59 | int spaceLen = op.left; 60 | for (int i = 0; i < children.length; i++) {// child和child之间填补空格,linesb是当前这些子节点上面的线 61 | VisualTree child = children[i]; 62 | String content = child.content; 63 | if (sb.length() < spaceLen) { 64 | sb.append(getFill(_SPACE, spaceLen - sb.length())); 65 | lineSb.append(getFill(_SPACE, spaceLen - lineSb.length())); 66 | } 67 | lineSb.append(getLine(content.length(), children.length - 1, i)); 68 | sb.append(content); 69 | toOperate.offer(child); 70 | } 71 | childCount += children.length; 72 | levelCount++; 73 | if (levelCount == levelLen) { 74 | allSb.append(lineSb + "\r\n"); 75 | allSb.append(sb + "\r\n"); 76 | lineSb.setLength(0); 77 | sb.setLength(0); 78 | levelCount = 0; 79 | levelLen = childCount; 80 | childCount = 0; 81 | } 82 | } 83 | return allSb.toString(); 84 | } 85 | private VisualTree(Tree tree, int leftOffset) { 86 | init(tree, leftOffset); 87 | } 88 | 89 | private VisualTree(IndexedWord tree, SemanticGraph root, int leftOffset) { 90 | init(tree, root, leftOffset); 91 | } 92 | 93 | private void init(Tree tree, int left) { 94 | this.label = tree.label().value(); 95 | this.left = left; 96 | Tree[] oriChildren = tree.children(); 97 | int width = 0; 98 | this.children = oriChildren.length > 0 ? new VisualTree[tree.children().length] : new VisualTree[0]; 99 | for (int i = 0; i < oriChildren.length; i++) { 100 | this.children[i] = new VisualTree(oriChildren[i], this.left + width); 101 | width += this.children[i].content.length(); 102 | } 103 | if (oriChildren.length > 0 && width < label.length()) { 104 | this.children[this.children.length - 1].setContent( 105 | getFill(_SPACE, label.length() - width) + this.children[this.children.length - 1].getContent()); 106 | width = label.length(); 107 | } 108 | int spaceLen = oriChildren.length > 0 ? (width - label.length() + 1) / 2 : SPACE_LEN; 109 | this.content = getFill(_SPACE, spaceLen) + label + getFill(_SPACE, spaceLen); 110 | } 111 | 112 | private void init(IndexedWord tree, SemanticGraph root, int left) { 113 | this.label = tree.toString(); 114 | this.left = left; 115 | root.edgeCount(); 116 | List oriChildren = root.getChildList(tree); 117 | int width = 0; 118 | this.children = oriChildren.size() > 0 ? new VisualTree[root.outDegree(tree)] : new VisualTree[0]; 119 | for (int i = 0; i < oriChildren.size(); i++) { 120 | IndexedWord child = oriChildren.get(i); 121 | this.children[i] = initRelation(tree, child, root, this.left + width); 122 | width += this.children[i].content.length(); 123 | } 124 | if (oriChildren.size() > 0 && width < label.length()) { 125 | this.children[this.children.length - 1].setContent( 126 | getFill(_SPACE, label.length() - width) + this.children[this.children.length - 1].getContent()); 127 | width = label.length(); 128 | } 129 | int spaceLen = oriChildren.size() > 0 ? (width - label.length() + 1) / 2 : SPACE_LEN; 130 | this.content = getFill(_SPACE, spaceLen) + label + getFill(_SPACE, spaceLen); 131 | } 132 | 133 | private VisualTree initRelation(IndexedWord tree, IndexedWord child, SemanticGraph root, int left) { 134 | String label = root.getEdge(tree, child).getRelation().toString(); 135 | VisualTree childNode = new VisualTree(child, root, left); 136 | int spaceLen = (childNode.content.length() - label.length() + 1) / 2; 137 | VisualTree relation = new VisualTree(left, new VisualTree[] { childNode }, 138 | getFill(_SPACE, spaceLen) + label + getFill(_SPACE, spaceLen), label); 139 | return relation; 140 | } 141 | 142 | private StringBuffer getLine(int contentLen, int end, int contentNum) { 143 | StringBuffer lineSb = new StringBuffer(); 144 | int frontLen = contentLen / 2; 145 | int backLen = contentLen % 2 == 0 ? contentLen / 2 - 1 : contentLen / 2; 146 | if (end == 0) { 147 | lineSb.append(getFill(_SPACE, frontLen)); 148 | lineSb.append(SINGLE_BAR); 149 | lineSb.append(getFill(_SPACE, backLen)); 150 | } else if (contentNum == 0) { 151 | lineSb.append(getFill(_SPACE, frontLen)); 152 | lineSb.append(LEFT_BAR); 153 | lineSb.append(getFill(_LINE, backLen)); 154 | } else if (contentNum == end) { 155 | lineSb.append(getFill(_LINE, frontLen)); 156 | lineSb.append(RIGHT_BAR); 157 | lineSb.append(getFill(_SPACE, backLen)); 158 | } else { 159 | lineSb.append(getFill(_LINE, frontLen)); 160 | lineSb.append(CONTINUED_BAR); 161 | lineSb.append(getFill(_LINE, backLen)); 162 | } 163 | return lineSb; 164 | } 165 | 166 | private static StringBuffer getFill(char fill, int n) { 167 | StringBuffer sb = new StringBuffer(); 168 | while (n-- > 0) 169 | sb.append(fill); 170 | return sb; 171 | } 172 | 173 | } --------------------------------------------------------------------------------