1

C# を使用してデータを収集しようとしています。独自の非標準的な方法でデータを出力するシステムがあります。このデータをフラット ファイルから定期的に解析し、データベースにインポートする必要があります。また、解析をできるだけ速く行う必要があります。私が正常に動作しているデータベースのものは簡単です。ファイルを解析する最善の方法を見つける手助けが必要です。現在、約 15000 行あり、毎日追加されています。ここでデータを見てみましょう。最初の行は、フラット ファイルでのデータの表示方法です。2 番目のビットは、インポートされるデータのビューを理解しやすくします。

{a test entry}  {{1}{{city}{chicago}{employee}{johnsmith}{building}{5}{room}{506A}{room}{506B}{id}{1234}}{2}{{city}{losangeles}{employee}{johnsmith}{building}{1}{room}{101A}{room}{102B}{id}{1234}}}

{a test entry}
{
    {1}

    {
        {city}      {chicago}
        {employee}  {johnsmith}
        {building}  {5}
        {room}      {506A}
        {room}      {506B}
        {id}        {1234}
    }

    {2}

    {
        {city}      {losangeles}
        {employee}  {johnsmith}
        {building}  {1}
        {room}      {101A}
        {id}        {1234}
    }
}

各エントリは、1 つのサブエントリ ({2} の下にデータがないことを意味します) のどこかにある場合もあれば、何百ものサブエントリになる場合もあります。

これを解析するにはどうすればよいですか?分割と部分文字列を使用していくつかのことを試みましたが、さまざまな成功を収めており、遅いです。

見ているデータを簡単に解析できる方法はありますか?

4

2 に答える 2

3

スタックを作成し、入力文字列を 1 文字ずつ処理します。

var stack = new Stack<StringBuilder>();
foreach (var ch in input)
{
    if (ch == '{')
    {
        stack.Push(new StringBuilder());
    }
    else if (ch == '}')
    {
        var item = stack.Pop().ToString();
        Console.WriteLine(new string(' ', stack.Count * 2) + item);
    }
    else if (stack.Count != 0)
    {
        stack.Peek().Append(ch);
    }
}

出力:

a test entry
  1
    city
    chicago
    employee
    johnsmith
    building
    5
    room
    506A
    room
    506B
    id
    1234

  2
    city
    losangeles
    employee
    johnsmith
    building
    1
    room
    101A
    room
    102B
    id
    1234

データを解析したので、あとはそれをどのデータ構造に入れるかを決める必要があります。

于 2013-03-01T01:22:49.560 に答える
0

このようなものはどうですか:

static void Main(string[] args)
{
    int index = 0;
    string text = "{a test entry}  {{1}{{city}{chicago}{employee}{johnsmith}{building}{5}{room}{506A}{room}{506B}{id}{1234}}{2}{{city}{losangeles}{employee}{johnsmith}{building}{1}{room}{101A}{room}{102B}{id}{1234}}}";

    var tokens = Tokenize(text);        
    var node = Parse(new Node(new Token() { TokenType = TokenType.Root, Value = string.Empty }), tokens, ref index);
    RaiseSubtrees(node);

    Console.WriteLine(node.ToString());
}

static List<Token> Tokenize(string text)
{
    Stack<StringBuilder> stack = new Stack<StringBuilder>();
    List<Token> tokens = new List<Token>();

    foreach (var ch in text)
    {
        if (ch == '{')
        {
            stack.Push(new StringBuilder());
            tokens.Add(new Token(TokenType.ObjectStart, "{" ));
        }
        else if (ch == '}')
        {
            var item = stack.Pop().ToString();

            if (!string.IsNullOrEmpty(item))
            {
                tokens.Add(new Token(TokenType.Text, item));
            }

            tokens.Add(new Token(TokenType.ObjectEnd, "}"));
        }
        else if (stack.Count != 0)
        {
            stack.Peek().Append(ch);
        }
    }

    return tokens;
}

static Node Parse(Node parent, List<Token> tokens, ref int index)
{
    for (; index < tokens.Count - 1; index++)
    {
        Token current = tokens[index];
        Token next = tokens[index + 1];

        if (current.TokenType == TokenType.ObjectStart)
        {
            Node child = new Node(current);
            parent.Children.Add(child);
            index++;
            Parse(child, tokens, ref index);
        }
        else if (current.TokenType == TokenType.Entry || current.TokenType == TokenType.Text)
        {
            Node child = new Node(current);
            parent.Children.Add(child);
        }
        else if (current.TokenType == TokenType.ObjectEnd)
        {
            return parent;
        }
    }

    return parent;
}

static void RaiseSubtrees(Node node)
{
    if (node.Children.Count == 1)
    {
        node.Token = node.Children.First().Token;
        node.Children.Clear();
    }
    else
    {
        foreach (Node child in node.Children)
        {
            RaiseSubtrees(child);
        }

        if (node.Children.All(c => c.Token.TokenType == TokenType.Text))
        {
            for (int i = node.Children.Count - 1; i >= 1; i-=2)
            {
                Node keyNode = node.Children[i - 1];
                Node valueNode = node.Children[i];
                keyNode.Token.TokenType = TokenType.Key;
                valueNode.Token.TokenType = TokenType.Value;

                Node newParent = new Node(new Token(TokenType.Property, string.Empty));
                newParent.Children.Add(keyNode);
                newParent.Children.Add(valueNode);

                node.Children.RemoveAt(i);
                node.Children.RemoveAt(i - 1);
                node.Children.Insert(i - 1, newParent);
            }
        }
    }
}

enum TokenType
{
    Entry,
    Key,
    ObjectStart,
    ObjectEnd,
    Property,
    Root,
    Text,
    Value
}

class Token
{
    public TokenType TokenType { get; set; }
    public string Value { get; set; }

    public Token()
    {
    }

    public Token(TokenType tokenType, string value)
    {
        this.TokenType = tokenType;
        this.Value = value;
    }
}

class Node
{
    public Token Token { get; set; }
    public IList<Node> Children { get; set; }

    public Node(Token token)
    {
        this.Token = token;
        this.Children = new List<Node>();
    }

    public override string ToString()
    {
        StringBuilder builder = new StringBuilder();
        ToString(this, builder, string.Empty);

        return builder.ToString();
    }

    public void ToString(Node parent, StringBuilder builder, string indent)
    {
        builder.Append(indent).Append(parent.Token.TokenType.ToString());

        if (parent.Token.TokenType != TokenType.Root && parent.Token.TokenType != TokenType.ObjectStart)
        {
            builder.Append(": ").Append(parent.Token.Value);
        }

        builder.Append("\n");

        foreach (var child in parent.Children)
        {
            ToString(child, builder, indent + "  ");
        }
    }
}

これは、トークン化に dtb と同様のアプローチを使用しますが、Nodeクラスを使用して、データをモデル化するツリーを作成します。これにより、より構造化された方法でデータを処理できるようになります。上記のメソッドの出力は次のMainようになります。

Root
  Text: a test entry
  ObjectStart
    Text: 1
    ObjectStart
      Property:
        Key: city
        Value: chicago
      Property:
        Key: employee
        Value: johnsmith
      Property:
        Key: building
        Value: 5
      Property:
        Key: room
        Value: 506A
      Property:
        Key: room
        Value: 506B
      Property:
        Key: id
        Value: 1234
    Text: 2
    ObjectStart
      Property:
        Key: city
        Value: losangeles
      Property:
        Key: employee
        Value: johnsmith
      Property:
        Key: building
        Value: 1
      Property:
        Key: room
        Value: 101A
      Property:
        Key: room
        Value: 102B
      Property:
        Key: id
        Value: 1234
于 2013-03-01T05:18:58.287 に答える