Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/api/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中缩进文本树的解析_Java_Algorithm - Fatal编程技术网

Java中缩进文本树的解析

Java中缩进文本树的解析,java,algorithm,Java,Algorithm,我有一个缩进文件需要用java解析, 我需要一些方法将其放在一个Section类中,如下所示 root root1 text1 text1.1 text1.2 text2 text2.1 text2.2 root2 text1 text1.1 text1.2 text2 text2.1

我有一个缩进文件需要用java解析, 我需要一些方法将其放在一个Section类中,如下所示

    root
     root1
       text1
         text1.1
         text1.2
       text2
         text2.1
         text2.2

     root2
       text1
         text1.1
         text1.2
       text2
         text2.1
         text2.2.2
我有一门课,用来放缩进的东西

public class Section 
{

    private List<Section> children;
    private String text;
    private int depth;
    public Section(String t)
    {
       text =t;
    }

    public List<Section> getChildren()
    {
        if (children == null)
      {
            children = new ArrayList<Section>();
       }
        return children;
}

public void setChildren(List<Section> newChildren)
{
    if (newChildren == null) {
        children = newChildren;
    } else {
        if (children == null) {
            children = new ArrayList<Section>();
        }
        for (Section child : newChildren) {
            this.addChild(child);
        }
    }
}

public void addChild(Section child)
{
    if (children == null) {
        children = new ArrayList<Section>();
    }
    if (child != null) {
        children.add(child);
    }
}

public String getText()
{
    return text;
}

public void setText(String newText)
{
    text =newText;
}
public String getDepth()
{
    return depth;
}

 public void setDepth(int newDepth)
 {
    depth = newDepth;
 }
}
公共类部分
{
私人名单儿童;
私有字符串文本;
私有整数深度;
公共部分(字符串t)
{
text=t;
}
公共列表getChildren()
{
if(children==null)
{
children=newarraylist();
}
返回儿童;
}
public void setChildren(列出newChildren)
{
if(newChildren==null){
儿童=新生儿童;
}否则{
if(children==null){
children=newarraylist();
}
用于(儿童部分:新儿童){
这个.addChild(child);
}
}
}
公共无效添加子项(子项部分)
{
if(children==null){
children=newarraylist();
}
if(child!=null){
添加(child);
}
}
公共字符串getText()
{
返回文本;
}
公共void setText(字符串newText)
{
文本=新文本;
}
公共字符串getDepth()
{
返回深度;
}
公共void setDepth(int newDepth)
{
深度=新深度;
}
}
我需要一些方法来解析文件,并将其放置在预期的结果中,这将为我们提供一个如下所示的Section对象

Section= 

Text="Root"
Children
Child1: Text= "root1" 

        Child1: "text1"
            Child1="Text 1.1"
            Child2="Text 1.2"
        Child2: "text2"
            Child1="Text 2.1"
            Child2="Text 2.2"
            Children
Child2: Text= "root2" 
        Child1: "text1"
            Child1="Text 1.1"
            Child2="Text 1.2"
        Child2: "text2"
            Child1="Text 2.1"
            Child2="Text 2.2"


Here is some code that I have started
   int indentCount=0;
   while(String text = reader.readline()
   {
   indentCount=countLeadingSpaces(String word);
   //TODO create the section here
   }


public static int countLeadingSpaces(String word)
{
    int length=word.length();
    int count=0;

   for(int i=0;i<length;i++)
   {
       char first = word.charAt(i); 
        if(Character.isWhitespace(first))
        {
            count++;           
        }
        else
        {
            return count;
        }
   }

 return count;

}
节=
Text=“Root”
儿童
Child1:Text=“root1”
Child1:“text1”
Child1=“文本1.1”
Child2=“文本1.2”
儿童2:“文本2”
Child1=“文本2.1”
Child2=“文本2.2”
儿童
Child2:Text=“root2”
Child1:“text1”
Child1=“文本1.1”
Child2=“文本1.2”
儿童2:“文本2”
Child1=“文本2.1”
Child2=“文本2.2”
下面是一些我已经开始的代码
int indentCount=0;
while(String text=reader.readline()
{
indentCount=对LeadingSpace(字符串字)进行计数;
//TODO在此处创建节
}
公共静态int countingsleadingspace(字符串字)
{
int length=word.length();
整数计数=0;

对于(inti=0;i这个令人惊讶的复杂问题…这里有一个伪代码

intialize a stack
push first line to stack
while (there are more lines to read) {
 S1 = top of stack // do not pop off yet
 S2 = read a line
 if depth of S1 < depth of S2 {
  add S2 as child of S1
  push S2 into stack
 }
 else {
  while (depth of S1 >= depth of S2 AND there are at least 2 elements in stack) {
   pop stack
   S1 = top of stack // do not pop
  }
  add S2 as child of S1
  push S2 into stack
 }
}
return bottom element of stack
初始化堆栈
将第一行推到堆栈
while(还有更多的行要读){
S1=堆栈顶部//尚未弹出
S2=读一行
如果S1深度=S2的深度,堆栈中至少有2个元素){
弹出堆栈
S1=堆栈顶部//不弹出
}
将S2添加为S1的子级
将S2推入堆栈
}
}
返回堆栈的底部元素
其中,depth是#前导空格。
您可能需要修改或包装Section类来存储线的深度。

我还添加了一个父指针。也许文本可以在没有父指针的情况下进行解析,但父指针使其更容易。首先,您需要更多的构造函数:

static final int root_depth = 4; // assuming 4 whitespaces precede the tree root

public Section(String text, int depth) {
    this.text     = text;
    this.depth    = depth;
    this.children = new ArrayList<Section>();
    this.parent   = null;
}

public Section(String text, int depth, Section parent) {
    this.text     = text;
    this.depth    = depth;
    this.children = new ArrayList<Section>();
    this.parent   = parent;
}
static final int root_depth=4;//假设树根前面有4个空格
公共部分(字符串文本,整数深度){
this.text=文本;
这个。深度=深度;
this.children=new ArrayList();
this.parent=null;
}
公共节(字符串文本、整型深度、节父级){
this.text=文本;
这个。深度=深度;
this.children=new ArrayList();
this.parent=parent;
}
然后,开始解析文件时,逐行读取:

Section prev = null;
for (String line; (line = bufferedReader.readLine()) != null; ) {
    if (prev == null && line begins with root_depth whitespaces) {
        Section root = new Section(text_of_line, root_depth);
        prev = root;
    }
    else {
        int t_depth = no. of whitespaces at the beginning of this line;
        if (t_depth > prev.getDepth())
            // assuming that empty sections are not allowed
            Section t_section = new Section(text_of_line, t_depth, prev);
            prev.addChild(t_section);
        }
        else if (t_depth == prev.getDepth) {
            Section t_section = new Section(text_of_line, t_depth, prev.getParent());
            prev.getParent().addChild(t_section);
        }
        else {
            while (t_depth < prev.getDepth()) {
                prev = prev.getParent();
            }
            // at this point, (t_depth == prev.getDepth()) = true
            Section t_section = new Section(text_of_line, t_depth, prev.getParent());
            prev.getParent().addChild(t_section);
        }
    }
}
Section prev=null;
for(字符串行;(line=bufferedReader.readLine())!=null;){
if(prev==null&&行以根深度空格开始){
截面根=新截面(文本线、根深度);
prev=根;
}
否则{
int t_depth=此行开头的空格数;
if(t_depth>prev.getDepth())
//假设不允许使用空节
截面t_截面=新截面(截面线的文本,t_深度,上一个);
上一个addChild(t_段);
}
else if(t_depth==prev.getDepth){
Section t_Section=新节(第行的文本,t_深度,prev.getParent());
prev.getParent().addChild(t_部分);
}
否则{
而(t_depth

我已经讨论了伪代码的一些细节,但我认为您已经了解了如何进行此解析的总体思路等。

我使用递归函数调用实现了另一种解决方案。据我估计,它的性能会比Max Seo的建议差,尤其是在深层层次上。不过,它更容易理解(在我看来),因此可以根据您的具体需要进行修改。请看一看,如果您有任何建议,请告诉我

一个好处是,它可以处理多根树,因为它是

问题描述-只是为了弄清楚。。。 假设我们有一个构造节点,它可以包含数据,并且有零个或多个 子节点,也是节点。基于文本输入,我们希望构建树 的节点,其中每个节点的数据是一行中的内容 节点在树中的位置由行位置和缩进表示, 因此,缩进的行是前一行的子行 凹痕较小

算法描述 假设我们有一个行列表,定义一个函数:

  • 如果输入列表至少有两行:
    • 从列表中删除第一行
    • 从列表中删除满足以下条件的所有行:
      • 具有比第一行更高的缩进
      • 在缩进小于或等于fir的下一行之前发生
        List<Node> LinesToTree( List<Line> lines )
        {
            if(lines.count >= 2)
            {
                firstLine = lines.shift
                nextLine = lines[0]
                children = List<Line>
        
                while(nextLine != null && firstLine.indent < nextLine.indent)
                {
                    children.add(lines.shift)
                    nextLine = lines[0]
                }
        
                firstLineNode = new Node
                firstLineNode.data = firstLine.data
                firstLineNode.children = LinesToTree(children)
        
                resultNodes = new List<Node>
                resultNodes.add(firstLineNode)
        
                if(lines.count > 0)
                {
                    siblingNodes = LinesToTree(lines)
                    resultNodes.addAll(siblingNodes)
                    return resultNodes
                }
                else
                {
                    return resultNodes
                }
            }
            elseif()
            {
                nodes = new List<Node>
                node = new Node
                node.data = lines[0].data
                node.children = new List<Node>
                return nodes
            }
            else
            {
                return new List<Node>
            }
        }
        
        public static function IndentedLinesToTreeArray(array $lineArrays, callable $getIndent = null, $childrenFieldName = "children")
        {
            //Default function to get element indentation
            if($getIndent == null){
                $getIndent = function($line){
                    return $line["indent"];
                };
            }
        
            $lineCount = count($lineArrays);
        
            if($lineCount >= 2)
            {
                $firstLine = array_shift($lineArrays);
                $children = [];
                $nextLine = $lineArrays[0];
        
                while($getIndent($firstLine) < $getIndent($nextLine)){
                    $children[] = array_shift($lineArrays);
                    if(!isset($lineArrays[0])){
                        break;
                    }
                    $nextLine = $lineArrays[0];
                }
        
                $firstLine[$childrenFieldName] = self::IndentedLinesToTreeArray($children, $getIndent, $childrenFieldName);
        
                if(count($lineArrays)){
                    return array_merge([$firstLine],self::IndentedLinesToTreeArray($lineArrays, $getIndent, $childrenFieldName));
                }else{
                    return [$firstLine];
                }
            }
            elseif($lineCount == 1)
            {
                $lineArrays[0][$childrenFieldName] = [];
                return $lineArrays;
            }
            else
            {
                return [];
            }
        }
        
        Test
            A
            B
            C
                C1
                C2
            D
        Something
            One
            Two
            Three
        
        var lines = new[]
        {
            "Test",
            "\tA",
            "\tB",
            "\tC",
            "\t\tC1",
            "\t\tC2",
            "\tD",
            "Something",
            "\tOne",
            "\tTwo",
            "\tThree"
        };
        
        var roots = IndentedTextToTreeParser.Parse(lines, 0, '\t');
        
        var dump = IndentedTextToTreeParser.Dump(roots);
        Console.WriteLine(dump);
        
        namespace MyNamespace
        {
            using System;
            using System.Collections.Generic;
            using System.Diagnostics;
            using System.Text;
        
            public static class IndentedTextToTreeParser
            {
                // https://stackoverflow.com/questions/21735468/parse-indented-text-tree-in-java
        
                public static List<IndentTreeNode> Parse(IEnumerable<string> lines, int rootDepth = 0, char indentChar = '\t')
                {
                    var roots = new List<IndentTreeNode>();
        
                    // --
        
                    IndentTreeNode prev = null;
        
                    foreach (var line in lines)
                    {
                        if (string.IsNullOrEmpty(line.Trim(indentChar)))
                            throw new Exception(@"Empty lines are not allowed.");
        
                        var currentDepth = countWhiteSpacesAtBeginningOfLine(line, indentChar);
        
                        if (currentDepth == rootDepth)
                        {
                            var root = new IndentTreeNode(line, rootDepth);
                            prev = root;
        
                            roots.Add(root);
                        }
                        else
                        {
                            if (prev == null)
                                throw new Exception(@"Unexpected indention.");
                            if (currentDepth > prev.Depth + 1)
                                throw new Exception(@"Unexpected indention (children were skipped).");
        
                            if (currentDepth > prev.Depth)
                            {
                                var node = new IndentTreeNode(line.Trim(), currentDepth, prev);
                                prev.AddChild(node);
        
                                prev = node;
                            }
                            else if (currentDepth == prev.Depth)
                            {
                                var node = new IndentTreeNode(line.Trim(), currentDepth, prev.Parent);
                                prev.Parent.AddChild(node);
        
                                prev = node;
                            }
                            else
                            {
                                while (currentDepth < prev.Depth) prev = prev.Parent;
        
                                // at this point, (currentDepth == prev.Depth) = true
                                var node = new IndentTreeNode(line.Trim(indentChar), currentDepth, prev.Parent);
                                prev.Parent.AddChild(node);
                            }
                        }
                    }
        
                    // --
        
                    return roots;
                }
        
                public static string Dump(IEnumerable<IndentTreeNode> roots)
                {
                    var sb = new StringBuilder();
        
                    foreach (var root in roots)
                    {
                        doDump(root, sb, @"");
                    }
        
                    return sb.ToString();
                }
        
                private static int countWhiteSpacesAtBeginningOfLine(string line, char indentChar)
                {
                    var lengthBefore = line.Length;
                    var lengthAfter = line.TrimStart(indentChar).Length;
                    return lengthBefore - lengthAfter;
                }
        
                private static void doDump(IndentTreeNode treeNode, StringBuilder sb, string indent)
                {
                    sb.AppendLine(indent + treeNode.Text);
                    foreach (var child in treeNode.Children)
                    {
                        doDump(child, sb, indent + @"    ");
                    }
                }
            }
        
            [DebuggerDisplay(@"{Depth}: {Text} ({Children.Count} children)")]
            public class IndentTreeNode
            {
                public IndentTreeNode(string text, int depth = 0, IndentTreeNode parent = null)
                {
                    Text = text;
                    Depth = depth;
                    Parent = parent;
                }
        
                public string Text { get; }
                public int Depth { get; }
                public IndentTreeNode Parent { get; }
                public List<IndentTreeNode> Children { get; } = new List<IndentTreeNode>();
        
                public void AddChild(IndentTreeNode child)
                {
                    if (child != null) Children.Add(child);
                }
            }
        }