问题
I have a text file which stores data in this manner:
Player name: NAME HERE Speed: 7 Strength: 9 Stamina: 4 Player name: ANOTHER NAME HERE Speed: 5 Strength: 8 Stamina: 3
The same file contains about fifteen different players, and I want to gather values from each of them, store in a temporary race variable, then calculate the mean value of the speed strength and stamina and present a winner. My first idea was to use regular expression but I am currently investigating if there are another, more sustainable way to do this.
This is for a side project of mine and any help is welcome. Thanks
回答1:
Define your Race Class Structure:
public class Race
{
public string Name;
public int Speed;
public int Strength;
public int Stamina;
}
Read your data in from your text file, and instantiate your Race
objects and collect them into a List<Race>
. Once collected you can call Average()
from your List
to get your results.
string[] myTextFileLines = File.ReadAllLines(myTextFile);
List<Race> myRaces = new List<Race>();
for (int i = 0; i < myTextFileLines.Length; i += 4)
{
myRaces.Add(new Race()
{
Name = myTextFileLines[i].Substring(myTextFileLines[i].IndexOf(":") + 2),
Speed = Convert.ToInt32(myTextFileLines[i + 1].Substring(myTextFileLines[i + 1].IndexOf(":") + 2)),
Strength = Convert.ToInt32(myTextFileLines[i + 2].Substring(myTextFileLines[i + 2].IndexOf(":") + 2)),
Stamina = Convert.ToInt32(myTextFileLines[i + 3].Substring(myTextFileLines[i + 3].IndexOf(":") + 2)),
});
}
Console.WriteLine("Avg Speed: {0}", myRaces.Average(r => Convert.ToDouble(r.Speed)));
Console.WriteLine("Avg Strength: {0}", myRaces.Average(r => Convert.ToDouble(r.Strength)));
Console.WriteLine("Avg Stamina: {0}", myRaces.Average(r => Convert.ToDouble(r.Strength)));
Console.ReadLine();
Results (using the exact data you provided in your question):
回答2:
An example of the XML solution:
Players.xml
<?xml version="1.0" encoding="utf-8" ?>
<players>
<player name="Alice">
<speed>7</speed>
<strength>9</strength>
<stamina>4</stamina>
</player>
<player name="Bob">
<speed>5</speed>
<strength>8</strength>
<stamina>3</stamina>
</player>
</players>
C# Code
private class Player
{
public string Name { get; set; }
public int Speed { get; set; }
public int Strength { get; set; }
public int Stamina { get; set; }
public override string ToString()
{
return "Name: " + Name + Environment.NewLine +
"Speed: " + Speed + Environment.NewLine +
"Strength: " + Strength + Environment.NewLine +
"Stamina: " + Stamina + Environment.NewLine;
}
}
private static void PrintXmlPlayers(XmlNode players)
{
foreach (XmlNode player in players.SelectNodes("player"))
{
string playerName = player.Attributes["name"].InnerText;
int playerSpeed = XmlConvert.ToInt32(player["speed"].InnerText);
int playerStrength = XmlConvert.ToInt32(player["strength"].InnerText);
int playerStamina = XmlConvert.ToInt32(player["stamina"].InnerText);
Player aPlayer = new Player
{
Name = playerName,
Speed = playerSpeed,
Strength = playerStrength,
Stamina = playerStamina
};
Console.WriteLine(aPlayer);
}
}
private static void TestXml()
{
// path of document is relative to executable
const string xmlPath = "../../Players.xml";
XmlDocument doc = new XmlDocument();
doc.Load(xmlPath);
XmlNode players = doc["players"];
PrintXmlPlayers(players);
XmlNode alice = players.SelectSingleNode("player[@name='Alice']");
string aliceOldString = alice["strength"].InnerText;
alice["strength"].InnerText = "10";
doc.Save(xmlPath);
PrintXmlPlayers(players);
alice["strength"].InnerText = aliceOldString;
doc.Save(xmlPath);
}
Output
Name: Alice
Speed: 7
Strength: 9
Stamina: 4
Name: Bob
Speed: 5
Strength: 8
Stamina: 3
Name: Alice
Speed: 7
Strength: 10
Stamina: 4
Name: Bob
Speed: 5
Strength: 8
Stamina: 3
回答3:
If the file format is fixed, one way to go about this is to use System.IO.File.ReadAllLines
to get every line in the file, and then loop over lines, splitting the key (left of the :
) and the value (right of the :
). Populate some sort of data object (PlayerObject
in below example) with the values that you read from the file as you process each line.
PlayerObject player = new PlayerObject();
string[] allLines = System.IO.File.ReadAllLines(FILE_PATH_HERE);
foreach(string dataPair in allLines)
{
string[] pair = dataPair.Split(new[] { ':' });
if(pair.Length == 2)
{
switch(pair[0])
{
case "Player name": /*process pair[1]*/ break;
case "Speed": /*process pair[1]*/ break;
//other possible key strings here
//recommend defining these as constants
}
}
}
This would allow you to re-order the parameters in the file (or support different orderings at least), and if any parameters are missing, they can be pre-set to some default value in the data object.
The only thing missing from your format would be some kind of sentinel value between records. Right now you could assume that each player is delineated by a new "Player name" entry, and start populating the next PlayerObject
once you read in the next "Player name".
来源:https://stackoverflow.com/questions/29832190/best-way-to-read-data-and-store-from-file