在 C# 中解析.dat文件并将其发送到 DTO



首先,该.dat文件的格式是这样的: (字符之间的空格是制表符,没有空格)。

VNUM    1   70
NAME    zts3e
INDEX   0   0   0   0   1   0
TYPE    0   1
FLAG    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
DATA    1   20  28  20  4   70  0   0   0   0   0   0   0   0   0   0   0   0   0   0
BUFF    -1  80  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
LINEDESC    1
zts4e
END
#========================================================
VNUM    2   400
NAME    zts5e
INDEX   0   0   0   0   2   0
TYPE    0   1
FLAG    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
DATA    4   29  43  32  4   70  0   0   0   0   0   0   0   0   0   0   0   0   0   0
BUFF    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
LINEDESC    1
zts6e
END
#========================================================
VNUM    3   910
NAME    zts7e
INDEX   0   0   0   0   3   2
TYPE    0   1
FLAG    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
DATA    7   39  57  44  4   70  0   0   0   0   0   0   0   0   0   0   0   0   0   0
BUFF    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
LINEDESC    1
zts8e
END
#========================================================

当我谷歌"文本格式化 C#" - 我得到的只是如何打开文本文件以及如何用 C# 编写文本文件。我不知道如何在文本文件中搜索文本。我发现的东西并没有像这样先进。

那么我如何为此构建解析器呢?将其添加到我的自定义 DTO 中并不是一件困难的事情,但解析所有这些文本是(因为我需要将该数字转换为字节、布尔值、短短裤、整数、长整型和我制作的一些自定义类型。

我非常感谢您的帮助,我认为这可能是一个愚蠢的问题,但我也是编程新手,我没有找到很多关于这方面的信息。

一个代码确实有效,但我不喜欢:

internal void ImportItems()
{
string fileId = $"{_folder}\Item.dat";
string fileLang = $"{_folder}\_code_{ConfigurationManager.AppSettings["Language"]}_Item.txt";
Dictionary<string, string> dictionaryName = new Dictionary<string, string>();
string line;
List<ItemDTO> items = new List<ItemDTO>();
using (StreamReader npcIdStream = new StreamReader(fileId, Encoding.GetEncoding(1252)))
{
ItemDTO item = new ItemDTO();
bool itemAreaBegin = false;
int itemCounter = 0;
while ((line = npcIdStream.ReadLine()) != null)
{
string[] currentLine = line.Split('t');
if (currentLine.Length > 3 && currentLine[1] == "VNUM")
{
itemAreaBegin = true;
item.VNum = short.Parse(currentLine[2]);
item.Price = long.Parse(currentLine[3]);
}
else if (currentLine.Length > 1 && currentLine[1] == "END")
{
if (!itemAreaBegin)
{
continue;
}
if (DAOFactory.ItemDAO.FirstOrDefault(s => s.VNum.Equals(item.VNum)) == null)
{
items.Add(item);
itemCounter++;
}
item = new ItemDTO();
itemAreaBegin = false;
}
else if (currentLine.Length > 2 && currentLine[1] == "NAME")
{
item.Name = dictionaryName.TryGetValue(currentLine[2], out string name) ? name : string.Empty;
}
else if (currentLine.Length > 7 && currentLine[1] == "INDEX")
{
switch (Convert.ToByte(currentLine[2]))
{
case 4:
item.Type = InventoryType.Equipment;
break;
case 8:
item.Type = InventoryType.Equipment;
break;
case 9:
item.Type = InventoryType.Main;
break;
case 10:
item.Type = InventoryType.Etc;
break;
default:
item.Type = (InventoryType)Enum.Parse(typeof(InventoryType), currentLine[2]);
break;
}
item.ItemType = currentLine[3] != "-1" ? (ItemType)Enum.Parse(typeof(ItemType), $"{(short)item.Type}{currentLine[3]}") : ItemType.Weapon;
item.ItemSubType = Convert.ToByte(currentLine[4]);
item.EquipmentSlot = (EquipmentType)Enum.Parse(typeof(EquipmentType), currentLine[5] != "-1" ? currentLine[5] : "0");
// item.DesignId = Convert.ToInt16(currentLine[6]);
switch (item.VNum)
{
// lots of cases
case 9115:
item.Morph = 3679;
item.Speed = 21;
item.WaitDelay = 3000;
break;
default:
if (item.EquipmentSlot.Equals(EquipmentType.Amulet))
{
switch (item.VNum)
// lots of cases
case 4503:
item.EffectValue = 4544;
default:
item.EffectValue = Convert.ToInt16(currentLine[7]);
break;
}
}
else
{
item.Morph = Convert.ToInt16(currentLine[7]);
}
break;
}
}
else if (currentLine.Length > 3 && currentLine[1] == "TYPE")
{
// currentLine[2] 0-range 2-range 3-magic
item.Class = item.EquipmentSlot == EquipmentType.Fairy ? (byte)15 : Convert.ToByte(currentLine[3]);
}
else if (currentLine.Length > 3 && currentLine[1] == "FLAG")
{
item.IsSoldable = currentLine[5] == "0";
item.IsDroppable = currentLine[6] == "0";
item.IsTradable = currentLine[7] == "0";
item.IsMinilandActionable = currentLine[8] == "1";
item.IsWarehouse = currentLine[9] == "1";
item.Flag9 = currentLine[10] == "1";
item.Flag1 = currentLine[11] == "1";
item.Flag2 = currentLine[12] == "1";
item.Flag3 = currentLine[13] == "1";
item.Flag4 = currentLine[14] == "1";
item.Flag5 = currentLine[15] == "1";
item.IsColored = currentLine[16] == "1";
item.Sex = currentLine[18] == "1" ? (byte)1 : currentLine[17] == "1" ? (byte)2 : (byte)0;
//not used item.Flag6 = currentLine[19] == "1";
item.Flag6 = currentLine[20] == "1";
if (currentLine[21] == "1")
{
item.ReputPrice = item.Price;
}
item.IsHeroic = currentLine[22] == "1";
item.Flag7 = currentLine[23] == "1";
item.Flag8 = currentLine[24] == "1";
}
else if (currentLine.Length > 1 && currentLine[1] == "DATA")
{
switch (item.ItemType)
{
case ItemType.Weapon:
item.LevelMinimum = Convert.ToByte(currentLine[2]);
item.DamageMinimum = Convert.ToInt16(currentLine[3]);
item.DamageMaximum = Convert.ToInt16(currentLine[4]);
item.HitRate = Convert.ToInt16(currentLine[5]);
item.CriticalLuckRate = Convert.ToByte(currentLine[6]);
item.CriticalRate = Convert.ToInt16(currentLine[7]);
item.BasicUpgrade = Convert.ToByte(currentLine[10]);
item.MaximumAmmo = 100;
break;
case ItemType.Armor:
item.LevelMinimum = Convert.ToByte(currentLine[2]);
item.CloseDefence = Convert.ToInt16(currentLine[3]);
item.DistanceDefence = Convert.ToInt16(currentLine[4]);
item.MagicDefence = Convert.ToInt16(currentLine[5]);
item.DefenceDodge = Convert.ToInt16(currentLine[6]);
item.DistanceDefenceDodge = Convert.ToInt16(currentLine[6]);
item.BasicUpgrade = Convert.ToByte(currentLine[10]);
break;
case ItemType.Box:
switch (item.VNum)
{
// lots of cases
case 287:
item.Effect = 69;
item.EffectValue = 1;
break;
default:
item.Effect = Convert.ToInt16(currentLine[2]);
item.EffectValue = Convert.ToInt32(currentLine[3]);
item.LevelMinimum = Convert.ToByte(currentLine[4]);
break;
}
break;
case ItemType.Fashion:
item.LevelMinimum = Convert.ToByte(currentLine[2]);
item.CloseDefence = Convert.ToInt16(currentLine[3]);
item.DistanceDefence = Convert.ToInt16(currentLine[4]);
item.MagicDefence = Convert.ToInt16(currentLine[5]);
item.DefenceDodge = Convert.ToInt16(currentLine[6]);
if (item.EquipmentSlot.Equals(EquipmentType.CostumeHat) || item.EquipmentSlot.Equals(EquipmentType.CostumeSuit))
{
item.ItemValidTime = Convert.ToInt32(currentLine[13]) * 3600;
}
break;
case ItemType.Food:
item.Hp = Convert.ToInt16(currentLine[2]);
item.Mp = Convert.ToInt16(currentLine[4]);
break;
case ItemType.Jewelery:
switch (item.EquipmentSlot)
{
case EquipmentType.Amulet:
item.LevelMinimum = Convert.ToByte(currentLine[2]);
break;
case EquipmentType.Fairy:
item.Element = Convert.ToByte(currentLine[2]);
item.ElementRate = Convert.ToInt16(currentLine[3]);
break;
default:
item.LevelMinimum = Convert.ToByte(currentLine[2]);
item.MaxCellonLvl = Convert.ToByte(currentLine[3]);
item.MaxCellon = Convert.ToByte(currentLine[4]);
break;
}
break;
case ItemType.Event:
switch (item.VNum)
{
// lots of cases
default:
item.EffectValue = Convert.ToInt16(currentLine[7]);
break;
}
break;
case ItemType.Special:
switch (item.VNum)
{
// lots of cases
default:
if (item.VNum > 5891 && item.VNum < 5900 || item.VNum > 9100 && item.VNum < 9109)
{
item.Effect = 69; // imagined number as for I = √(-1), complex z = a + bi
}
else
{
item.Effect = Convert.ToInt16(currentLine[2]);
}
break;
}
switch (item.Effect)
{
case 150:
case 151:
if (Convert.ToInt32(currentLine[4]) == 1)
{
item.EffectValue = 30000;
}
else if (Convert.ToInt32(currentLine[4]) == 2)
{
item.EffectValue = 70000;
}
else if (Convert.ToInt32(currentLine[4]) == 3)
{
item.EffectValue = 180000;
}
else
{
item.EffectValue = Convert.ToInt32(currentLine[4]);
}
break;
case 204:
item.EffectValue = 10000;
break;
case 305:
item.EffectValue = Convert.ToInt32(currentLine[5]);
item.Morph = Convert.ToInt16(currentLine[4]);
break;
default:
item.EffectValue = item.EffectValue == 0 ? Convert.ToInt32(currentLine[4]) : item.EffectValue;
break;
}
item.WaitDelay = 5000;
break;
case ItemType.Magical:
if (item.VNum > 2059 && item.VNum < 2070)
{
item.Effect = 10;
}
else
{
item.Effect = Convert.ToInt16(currentLine[2]);
}
item.EffectValue = Convert.ToInt32(currentLine[4]);
break;
case ItemType.Specialist:
// item.isSpecialist = Convert.ToByte(currentLine[2]); item.Unknown = Convert.ToInt16(currentLine[3]);
item.ElementRate = Convert.ToInt16(currentLine[4]);
item.Speed = Convert.ToByte(currentLine[5]);
item.SpType = Convert.ToByte(currentLine[13]);
// item.Morph = Convert.ToInt16(currentLine[14]) + 1;
item.FireResistance = Convert.ToByte(currentLine[15]);
item.WaterResistance = Convert.ToByte(currentLine[16]);
item.LightResistance = Convert.ToByte(currentLine[17]);
item.DarkResistance = Convert.ToByte(currentLine[18]);
// item.PartnerClass = Convert.ToInt16(currentLine[19]);
item.LevelJobMinimum = Convert.ToByte(currentLine[20]);
item.ReputationMinimum = Convert.ToByte(currentLine[21]);
Dictionary<int, int> elementdic = new Dictionary<int, int> { { 0, 0 } };
if (item.FireResistance != 0)
{
elementdic.Add(1, item.FireResistance);
}
if (item.WaterResistance != 0)
{
elementdic.Add(2, item.WaterResistance);
}
if (item.LightResistance != 0)
{
elementdic.Add(3, item.LightResistance);
}
if (item.DarkResistance != 0)
{
elementdic.Add(4, item.DarkResistance);
}
item.Element = (byte)elementdic.OrderByDescending(s => s.Value).First().Key;
if (elementdic.Count > 1 && elementdic.OrderByDescending(s => s.Value).First().Value == elementdic.OrderByDescending(s => s.Value).ElementAt(1).Value)
{
item.SecondaryElement = (byte)elementdic.OrderByDescending(s => s.Value).ElementAt(1).Key;
}
// needs to be hardcoded
switch (item.VNum)
{
case 901:
item.Element = 1;
break;
case 903:
item.Element = 2;
break;
case 906:
item.Element = 3;
break;
case 909:
item.Element = 3;
break;
}
break;
case ItemType.Shell:
// item.ShellMinimumLevel = Convert.ToInt16(linesave[3]);
// item.ShellMaximumLevel = Convert.ToInt16(linesave[4]);
// item.ShellType = Convert.ToByte(linesave[5]); // 3 shells of each type
break;
case ItemType.Main:
item.Effect = Convert.ToInt16(currentLine[2]);
item.EffectValue = Convert.ToInt32(currentLine[4]);
break;
case ItemType.Upgrade:
item.Effect = Convert.ToInt16(currentLine[2]);
switch (item.VNum)
{
// UpgradeItems (needed to be hardcoded)
case 1218:
item.EffectValue = 26;
break;
case 1363:
item.EffectValue = 27;
break;
case 1364:
item.EffectValue = 28;
break;
case 5107:
item.EffectValue = 47;
break;
case 5207:
item.EffectValue = 50;
break;
case 5369:
item.EffectValue = 61;
break;
case 5519:
item.EffectValue = 60;
break;
default:
item.EffectValue = Convert.ToInt32(currentLine[4]);
break;
}
break;
case ItemType.Production:
item.Effect = Convert.ToInt16(currentLine[2]);
item.EffectValue = Convert.ToInt32(currentLine[4]);
break;
case ItemType.Map:
item.Effect = Convert.ToInt16(currentLine[2]);
item.EffectValue = Convert.ToInt32(currentLine[4]);
break;
case ItemType.Potion:
item.Hp = Convert.ToInt16(currentLine[2]);
item.Mp = Convert.ToInt16(currentLine[4]);
break;
case ItemType.Snack:
item.Hp = Convert.ToInt16(currentLine[2]);
item.Mp = Convert.ToInt16(currentLine[4]);
break;
case ItemType.Teacher:
item.Effect = Convert.ToInt16(currentLine[2]);
item.EffectValue = Convert.ToInt32(currentLine[4]);
// item.PetLoyality = Convert.ToInt16(linesave[4]); item.PetFood = Convert.ToInt16(linesave[7]);
break;
case ItemType.Part:
// nothing to parse
break;
case ItemType.Sell:
// nothing to parse
break;
case ItemType.Quest2:
// nothing to parse
break;
case ItemType.Quest1:
// nothing to parse
break;
case ItemType.Ammo:
// nothing to parse
break;
}
if (item.Type == InventoryType.Miniland)
{
item.MinilandObjectPoint = int.Parse(currentLine[2]);
item.EffectValue = short.Parse(currentLine[8]);
item.Width = Convert.ToByte(currentLine[9]);
item.Height = Convert.ToByte(currentLine[10]);
}
if (item.EquipmentSlot != EquipmentType.Boots && item.EquipmentSlot != EquipmentType.Gloves || item.Type != 0)
{
continue;
}
item.FireResistance = Convert.ToByte(currentLine[7]);
item.WaterResistance = Convert.ToByte(currentLine[8]);
item.LightResistance = Convert.ToByte(currentLine[9]);
item.DarkResistance = Convert.ToByte(currentLine[11]);
}
else if (currentLine.Length > 1 && currentLine[1] == "BUFF")
{
for (int i = 0; i < 5; i++)
{
byte type = (byte)int.Parse(currentLine[2 + 5 * i]);
if (type == 0 || type == 255)
{
continue;
}
int first = int.Parse(currentLine[3 + 5 * i]);
BCardDTO itemCard = new BCardDTO
{
ItemVNum = item.VNum,
Type = type,
SubType = (byte)((int.Parse(currentLine[5 + 5 * i]) + 1) * 10 + 1),
IsLevelScaled = Convert.ToBoolean(first % 4),
IsLevelDivided = (first % 4) == 2,
FirstData = (short)(first / 4),
SecondData = (short)(int.Parse(currentLine[4 + 5 * i]) / 4),
ThirdData = (short)(int.Parse(currentLine[6 + 5 * i]) / 4),
};
itemCards.Add(itemCard);
}
}
}
}
}

PD:我想补充一点,我不能手动完成,因为这个.dat有 52306 行,不可能做到这一点

你可以这样做。解析所有行并将其添加到对象中。 例如,创建一个DTO 对象

class DTO
{
string Name{get;set;}
List<short> Index{get;set;}
//etc
}

并将行解析为DTO 对象

var lines = System.IO.File.ReadAllLines("somedoc.txt");
List<DTO> dtos = new List<DTO>();
foreach(var line in lines)
{
Console.WriteLine(line);
//split it to words
var lineFields = line.Split(null);
//first will be the field's value
var field = lineFields.FirstOrDefault(f => !string.IsNullOrEmpty(f));
//others will be the field's values
var values = line.Where(val => !string.IsNullOrEmpty(val) && !string.Equals(field, val)).Select(elem => short.Parse(elem)).ToList();
DTO dtoObj = new DTO();
if(field.Equals("NAME"))dtoObj.Name = field;
if(field.Equals("INDEX")) dtoObj.Index.AddRange(values);
if(line.Contains("END")
{
//end it, and parse it to next object.
}
}

这不是一个完整的示例,但您可以通过这种方式开始工作。

最终解决方案:

public string[] getBlocks(string path)
{
string[] blocks = File.ReadAllText(path).Split(new string[] { "#========================================================" }, StringSplitOptions.None);
return blocks;
}
public Dictionary<string, string[]> getValues(string block)
{
Dictionary<string, string[]> dictionary = new Dictionary<string, string[]>();
var foos = new List<string>(Regex.Split(block, "t"));
foos.RemoveAt(0);
string[] values = Regex.Split(String.Join("t", foos.ToArray()), "r");
values = values.Take(values.Count() - 1).ToArray();
foreach (string value in values)
{
string[] fieldName = Regex.Split(value, "t");
fieldName = fieldName.Where(x => !string.IsNullOrEmpty(x)).ToArray();
var newList = new List<string>(fieldName);
if(newList.Count >= 1)
{
newList.RemoveAt(0);
string[] valueList = newList.ToArray();
dictionary.Add(fieldName[0], valueList);
}
else
{
}
}
return dictionary;
}

相关内容

  • 没有找到相关文章

最新更新