Reputation: 3
I have run into an issue while iterating through the lines of a file. This file has thousands of lines and they look like this:
# Tibia - graphical Multi-User-Dungeon
# MonsterHomes File
# Race X Y Z Radius Amount Regen.
# ====== 0997,0988,09 ====================
50 31927 31622 9 50 3 700
# ====== 0997,0989,09 ====================
7 31931 31657 9 50 2 700
# ====== 0997,0990,09 ====================
5 31914 31691 9 50 4 600
50 31915 31687 9 50 2 650
# ====== 0997,0991,09 ====================
26 31930 31712 9 50 1 700
45 31925 31719 9 50 3 600
# ====== 0998,0986,10 ====================
49 31947 31564 10 50 1 900
# ====== 0998,0987,08 ====================
52 31958 31604 8 50 3 600
# ====== 0998,0987,10 ====================
49 31947 31586 10 50 2 900
# ====== 0998,0988,08 ====================
26 31963 31637 8 50 2 500
30 31961 31619 8 50 3 600
45 31945 31620 8 50 2 700
# ====== 0998,0988,09 ====================
5 31944 31618 9 50 1 600
5 31953 31623 9 50 4 700
5 31963 31631 9 50 1 600
7 31950 31624 9 50 1 650
36 31946 31630 9 50 1 600
# ====== 0998,0989,08 ====================
26 31954 31677 8 50 1 500
26 31948 31674 8 50 2 500
36 31942 31670 8 50 1 600
# ====== 0998,0989,09 ====================
19 31960 31676 9 50 4 700
# ====== 0998,0990,06 ====================
31 31950 31708 6 50 3 600
# ====== 0998,0990,08 ====================
What I am trying to do is that, whenever # ======
appears at the beginning of a line, a new object called Spawn will be created. And then I will go through that line and all the lines below, until the next # ======
and repeat. First I want to skip the top 5 lines in the file though.
So let's take the text above as example. So the first "Spawn" object should be focusing on this segment:
# ====== 0997,0988,09 ====================
50 31927 31622 9 50 3 700
The next one will be:
# ====== 0997,0989,09 ====================
7 31931 31657 9 50 2 700
And the third one:
# ====== 0997,0990,09 ====================
5 31914 31691 9 50 4 600
50 31915 31687 9 50 2 650
And it will continue like that.
I have managed to create a new object when the line begins with # ======
, but how do I read the lines below until the next occurence of # ======
?
static void Main(string[] args)
{
// Step 1. Read all lines in monster.db file - skip the first 5 lines
foreach (string line in File.ReadLines("monster.db").Skip(5))
{
if (line.StartsWith("# ======"))
{
// BEGIN SPAWN
Spawn spawn = new Spawn();
// Step 2. Get the sector file name
string filename = line.Replace(" ", "").Replace("=", "").Replace("#", "").Replace(",", "-") + ".sec";
spawn.SectorFile = filename;
// Step 3. Read the lines below until the next occurence of "# ======"
// And add the values to the object
spawn.xxxxx = the values
}
}
}
I don't need help with getting the actual values. I just help to find out how I can divide this text file into smaller pieces. And each object will be created whenever a line starts with # ======
. I need to read that line and the lines below, until next occurance.
Please let me know if it's unclear. I try to explain as best as I can.
Image explaining it: https://i.sstatic.net/Lu1u4.png
Updated code:
// List of spawns
public static List<Spawn> Spawns = new List<Spawn> { };
public static Spawn spawn = null;
// List of already used coordinates
public static List<Position> Positions = new List<Position> { };
public static Random rnd = new Random();
static void Main(string[] args)
{
// Step 1. Read all lines in monster.db file - skip the first 5 lines
foreach (string line in File.ReadLines("monster.db").Skip(5))
{
if (line.StartsWith("# ======"))
{
// BEGIN SPAWN
spawn = new Spawn();
// Step 2. Get the sector file name
string filename = line.Replace(" ", "").Replace("=", "").Replace("#", "").Replace(",", "-") + ".sec";
spawn.SectorFile = filename;
Spawns.Add(spawn);
}
// Continue to the next segment if no more monster lines
if (spawn == null)
continue;
// Step 3. Get the monsters
if (!line.Contains("#") && line.Length >= 10)
{
string replaceSpace = line.Replace(" ", "-");
string removeDuplicateDash = Regex.Replace(replaceSpace, @"\-+", "-");
string dashed = removeDuplicateDash.Substring(1);
spawn.MonsterId = Int32.Parse(dashed.Split('-').FirstOrDefault());
spawn.SpawnX = Int32.Parse(dashed.Split('-').Skip(1).FirstOrDefault());
spawn.SpawnY = Int32.Parse(dashed.Split('-').Skip(2).FirstOrDefault());
spawn.SpawnZ = Int32.Parse(dashed.Split('-').Skip(3).FirstOrDefault());
spawn.Radius = Int32.Parse(dashed.Split('-').Skip(4).FirstOrDefault());
spawn.Amount = Int32.Parse(dashed.Split('-').Skip(5).FirstOrDefault());
spawn.Regen = Int32.Parse(dashed.Split('-').Skip(6).FirstOrDefault());
}
}
// List all the spawns
foreach (Spawn s in Spawns)
{
Console.WriteLine($"{s.SectorFile} - {s.MonsterId}, [{s.SpawnX}, {s.SpawnY}, {s.SpawnZ}] - Amount: {s.Amount} - Radius: {s.Radius}");
}
}
Upvotes: 0
Views: 103
Reputation: 750
Now I that I really understand what the OP wants :) here is it
string spawnHeader = null;
foreach (string line in File.ReadLines("monster.db").Skip(5))
{
if (line.StartsWith("# ======"))
{
string filename = line.Replace(" ", "").Replace("=", "").Replace("#", "").Replace(",", "-") + ".sec";
spawnHeader = filename;
}
if (spawnHeader == null)
continue;
if (!line.Contains("#") && line.Length >= 10)
{
var spawn = new Spawn();
spawn.MonsterId = ....
...
spawn.SectorFile = spawnHeader;
Spawns.Add(spawn);
}
}
Upvotes: 1
Reputation: 39142
Just track the "current" sector filename in a variable outside the loop and use that:
List<Spawn> Spawns = new List<Spawn>();
string curSectorFile = "";
// Step 1. Read all lines in monster.db file - skip the first 5 lines
foreach (string line in File.ReadLines("monster.db").Skip(5))
{
if (line.StartsWith("# ======"))
{
// Step 2. Get the sector file name
string filename = line.Replace(" ", "").Replace("=", "").Replace("#", "").Replace(",", "-") + ".sec";
curSectorFile = filename;
}
else if(curSectorFile != "")
{
Spawn sp = new Spawn();
sp.SectorFile = curSectorFile;
// parse "line"...
sp.xxx = yyy;
sp.xxx = yyy;
sp.xxx = yyy;
sp.xxx = yyy;
// add it to some kind of List<>?
Spawns.Add(sp);
}
}
Upvotes: 0
Reputation: 34421
Try following. Code been fully tested. No need to skip lines. Just you the # at beginning of line to indicate where data starts. :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication4
{
class Program
{
const string FILENAME = @"c:\temp\test.txt";
static void Main(string[] args)
{
List<Monster> monsters = new List<Monster>();
Monster monster = null;
StreamReader reader = new StreamReader(FILENAME);
string line = "";
string[] splitLine;
while ((line = reader.ReadLine()) != null)
{
line = line.Trim();
if (line.Length > 0)
{
if (line.StartsWith("#"))
{
if (line.StartsWith("# ======"))
{
splitLine = line.Split(new char[] { '#', ' ', '=' }, StringSplitOptions.RemoveEmptyEntries);
string id = splitLine[0];
monster = new Monster();
monster.id = id;
monsters.Add(monster);
}
}
else
{
splitLine = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (monster.homes == null) monster.homes = new List<Home>();
Home home = new Home()
{
Race = int.Parse(splitLine[0]),
X = int.Parse(splitLine[1]),
Y = int.Parse(splitLine[2]),
Z = int.Parse(splitLine[3]),
Radius = int.Parse(splitLine[4]),
Amount = int.Parse(splitLine[5]),
Regen = int.Parse(splitLine[6])
};
monster.homes.Add(home);
}
}
}
}
}
public class Monster
{
public string id { get; set; }
public List<Home> homes { get; set; }
}
public class Home
{
public int Race { get; set; }
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
public int Radius { get; set; }
public int Amount { get; set; }
public int Regen { get; set; }
}
}
Upvotes: 0