207 lines
7.2 KiB (Stored with Git LFS)
C#
207 lines
7.2 KiB (Stored with Git LFS)
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
namespace Superlazy.Loader
|
|
{
|
|
public static class YamlLoader
|
|
{
|
|
public static SLEntity LoadYaml(string yamlString)
|
|
{
|
|
var root = SLEntity.Empty;
|
|
LoadYaml(root, yamlString);
|
|
return root;
|
|
}
|
|
|
|
public static void LoadYaml(SLEntity root, string yamlString)
|
|
{
|
|
var currentEntity = root;
|
|
var stack = new Stack<Tuple<SLEntity, int>>();
|
|
|
|
using var reader = new StringReader(yamlString);
|
|
string line;
|
|
while ((line = reader.ReadLine()) != null)
|
|
{
|
|
var lineBegin = 0;
|
|
while (lineBegin < line.Length && line[lineBegin] == ' ') lineBegin++;
|
|
|
|
if (line.Length <= lineBegin) continue;
|
|
|
|
var separatorIndex = line.IndexOf(':');
|
|
string key;
|
|
var isArray = false;
|
|
if (separatorIndex == -1)
|
|
{
|
|
if (line[lineBegin] == '#')
|
|
{
|
|
continue;
|
|
}
|
|
else if (line[lineBegin] == '-')
|
|
{
|
|
isArray = true;// 배열 전용 처리
|
|
key = null;
|
|
separatorIndex = lineBegin;
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var commentIndex = line.IndexOf('#');
|
|
if (commentIndex >= 0 && commentIndex <= separatorIndex) // 키에는 주석을 넣을수 없기 때문에 구분자 이전은 주석
|
|
{
|
|
continue; // 전체 주석
|
|
}
|
|
else
|
|
{
|
|
key = line.Substring(lineBegin, separatorIndex - lineBegin);
|
|
}
|
|
}
|
|
|
|
var valueBegin = separatorIndex + 2;
|
|
var valueEnd = line.Length;
|
|
|
|
if (valueBegin + 1 < valueEnd)
|
|
{
|
|
var commentIndex = line.IndexOf('#', valueBegin, valueEnd - valueBegin);
|
|
// TODO: 문자열 내의 #은 인식 못하도록 현재가 문자열 내부인지 체크가 필요
|
|
if (commentIndex >= 0 && (commentIndex == 0 || line[commentIndex - 1] == ' ')) // 빈칸이 하나 있어야 주석임
|
|
{
|
|
valueEnd = commentIndex - 1;
|
|
}
|
|
|
|
while (valueEnd > valueBegin && line[valueBegin] == ' ')
|
|
{
|
|
valueBegin++;
|
|
}
|
|
|
|
while (valueEnd >= valueBegin && line[valueEnd - 1] == ' ')
|
|
{
|
|
valueEnd--;
|
|
}
|
|
}
|
|
|
|
while (stack.Count > 0 && lineBegin <= stack.Peek().Item2)
|
|
{
|
|
currentEntity.EndModified();
|
|
currentEntity = stack.Pop().Item1;
|
|
}
|
|
|
|
if (isArray)
|
|
{
|
|
key = (currentEntity.Count() + 1).ToString();
|
|
}
|
|
|
|
if (valueBegin >= valueEnd)
|
|
{
|
|
stack.Push(new Tuple<SLEntity, int>(currentEntity, lineBegin));
|
|
currentEntity = currentEntity[key];
|
|
}
|
|
else
|
|
{
|
|
var forceString = false;
|
|
|
|
if (line[valueBegin] == '"' && line[valueEnd - 1] == '"' || line[valueBegin] == '\'' && line[valueEnd - 1] == '\'')
|
|
{
|
|
valueBegin += 1;
|
|
valueEnd -= 1;
|
|
forceString = true;
|
|
}
|
|
|
|
var value = line.Substring(valueBegin, valueEnd - valueBegin);
|
|
|
|
if (forceString)
|
|
{
|
|
currentEntity[key] = value;
|
|
}
|
|
else if (int.TryParse(value, out var intValue))
|
|
{
|
|
currentEntity[key] = intValue;
|
|
}
|
|
else if (double.TryParse(value, out var doubleValue))
|
|
{
|
|
currentEntity[key] = doubleValue;
|
|
}
|
|
else
|
|
{
|
|
currentEntity[key] = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
while (stack.Count > 0)
|
|
{
|
|
currentEntity.EndModified();
|
|
currentEntity = stack.Pop().Item1;
|
|
}
|
|
}
|
|
|
|
public static string SaveToYaml(SLEntity entity, int indentation = 0, bool useArray = false)
|
|
{
|
|
var yamlString = new StringBuilder();
|
|
|
|
var index = 1;
|
|
|
|
IEnumerable<SLEntity> childs = entity;
|
|
if (useArray && entity.All(x => int.TryParse(x.ID, out _)))
|
|
{
|
|
childs = entity.OrderBy(x => int.Parse(x.ID));
|
|
}
|
|
else // 전부 int로 파싱 못하면, 배열로 처리하지 않음
|
|
{
|
|
useArray = false;
|
|
}
|
|
|
|
foreach (var child in childs)
|
|
{
|
|
var key = child.ID;
|
|
var value = child;
|
|
|
|
if (useArray && index > 0 && key == index.ToString())
|
|
{
|
|
key = "-";
|
|
++index;
|
|
yamlString.Append(' ', indentation).Append(key);
|
|
}
|
|
else
|
|
{
|
|
index = -1;
|
|
yamlString.Append(' ', indentation).Append(key).Append(':');
|
|
}
|
|
|
|
if (value.IsValue)
|
|
{
|
|
var valueString = value.ToString();
|
|
var needsQuotes =
|
|
value.IsNumeric == false && (int.TryParse(valueString, out _) || double.TryParse(valueString, out _)) // 숫자인데 강제로 문자화 한거거나
|
|
|| valueString.Contains('#') || valueString.StartsWith('[') || valueString.StartsWith('{') // 특수문자가 포함되어 있거나, 배열이나 객체로 시작하는 경우 {Value}
|
|
|| valueString.Contains(':') // "남은 시간: {Value}" 꼴
|
|
|| (value.IsNumeric == false && valueString.StartsWith('-')); // "- 어쩌고" 꼴, 배열인것으로 이해
|
|
|
|
yamlString.Append(' ');
|
|
|
|
if (needsQuotes)
|
|
{
|
|
yamlString.Append('"').Append(valueString.Replace("\"", "\\\"")).Append('"');
|
|
}
|
|
else
|
|
{
|
|
yamlString.Append(valueString);
|
|
}
|
|
|
|
yamlString.Append(Environment.NewLine);
|
|
}
|
|
else
|
|
{
|
|
yamlString.Append(Environment.NewLine).Append(SaveToYaml(value, indentation + 2, useArray));
|
|
}
|
|
}
|
|
|
|
return yamlString.ToString();
|
|
}
|
|
}
|
|
} |