Can anyone help me. I'm trying to modify the yaml config.
This is the sample yaml:
person:
# some comments
name: "Test"
# some comments
age: 20
I want to modify only the age without affecting like comments and other infos.
And then save it again to file.
But in my trial, the comments is not being save but only the deserialized data.
Thank you.
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using var reader = new StreamReader("test.yaml");
var scanner = new Scanner(reader, skipComments: false);
var parser = new Parser(scanner);
//using var writer = new StreamWriter("test2.yaml");
//var emitter = new Emitter(writer);
var emitter = new Emitter(Console.Out);
while (parser.MoveNext())
{
if (parser.Current is Scalar scalar)
{
if (scalar.IsKey && scalar.Value == "age")
{
emitter.Emit(scalar);
parser.MoveNext(); // move to age value
emitter.Emit(new Scalar("30")); // new age value
continue;
}
}
emitter.Emit(parser.Current);
}
It almost works. The following result is obtained:
person
# some comments
:
name: "Test"
# some comments
age: 30
The emitter violates the output. A colon is placed after the comment.
Do further research yourself.
A method receives an object list each entity has the following attributes:
name
room
The list contains, for example, the following objects:
name: pc01 room: a1
name: pc02 room: a1
name: pc01 room: XYZ
name: pc02 room: XYZ
name: pc03 room: XYZ
The number of rooms and pc is not known before the program start, as well as the name of the rooms.
I would like to create a file for each room.
Each object should be printed in a line of the object.
For the example above it would mean:
File 1
File-Name = a1.txt
File-Content:{
pc01a1
pc02a1
}
File 2
File-Name = XYZ.txt
File-Content:{
pc01XYZ
pc02XYZ
pc03XYZ
}
I know how to loop the object-list and how to write into files, but I don't know, how to create dynamic file names.
I tried the following (results = list of objects):
foreach (PC currentPc in results)
{
//Path to the writer in relation to the attribute room
var pathFile = "D:\\" + currentPc.room + ".txt";
StreamWriter writerRoom = new StreamWriter(pathFile);
//Write Line
writerRoom.WriteLine(currentPc.room.ToLower() + currentPc.name.ToLower());
//Close Writer
writerRoom.Close();
}
The code creates the correct files for each room. The problem is, that each file only contains the last object of the list. I would like to have each object of that room.
Each time you encounter the same room again, you are overwriting the file you just created. Instead use AppendAllText:
foreach (PC currentPc in results)
{
// Path to file in relation to the attribute room
var filePath = $#"D:\{currentPc.room}.txt";
var textToAppend = $"{currentPc.room.ToLower()}{currentPc.name.ToLower()}\r\n";
System.IO.File.AppendAllText(filePath, textToAppend);
}
This method creates the file if it doesn't exist, appends to it and closes it again. \r\n is a line break to make it look nice.
EDIT:
To empty/delete the files you would need a separate loop to run before the generating one:
// Delete all files before running generating loop
foreach (PC currentPc in results)
{
var filePath = $#"D:\{currentPc.room}.txt";
// Check to see if the file exists
if (System.IO.File.Exists(filePath))
{
System.IO.File.Delete(filePath);
}
}
I want to to be able to pass in the name of the item I want to delete from the list.
But when I debug out the variable that comes through, it gives me:
Car Name: Happy Car
What Do I need to do to eliminate the extra letters?
Do I need to use `CharToTrim'?
Thanks for the help in advance...
if(File.Exists(Application.persistentDataPath + "/JSON/dbindex.json"))
{
//Load in JSON file
string dbindex = File.ReadAllText (Application.persistentDataPath + "/JSON/dbindex.json");
//Load file in as an array
DatabaseIndex[] _tempLoadIndexList = JsonHelper.FromJson<DatabaseIndex> (dbindex);
//Convert to List
DBIndexList = _tempLoadIndexList.OfType<DatabaseIndex>().ToList();
for (int i = 0; i < DBIndexList.Count; i++)
{
if (DBIndexList[i].DatabaseName == dbname)
{
DBIndexList.Remove(DBIndexList[i]);
}
}
If I replace dbname in the for loop with the text "Happy Car" it works. When I use my variable in there, it does not.
if (DBIndexList[i].DatabaseName == dbname.Replace("Car Name: ", string.Empty))
{
DBIndexList.Remove(DBIndexList[i]);
}
Another way (case insensitive also)
string dbNameTrimmed = dbname.TrimStart("Car Name: ".ToCharArray());
if(DBIndexList[i].DatabaseName.Equals(dbNameTrimmed, StringComparison.OrdinalIgnoreCase))
{
DBIndexList.Remove(DBIndexList[i]);
}
Basically I have a text file of records in this format:
(1909, 'Ford', 'Model T'),
(1926, 'Chrysler', 'Imperial'),
(1948, 'Citroën', '2CV'),
That I want to output to a text file in the following format
new Vehicle() { Id = 1, Year = 1909, Make = "Ford", Model = "Model T" },
new Vehicle() { Id = 2, Year = 1926, Make = "Chrysler", Model = "Imperial" },
new Vehicle() { Id = 3, Year = 1948, Make = "Citroën", Model = "2CV" },
I know I need to split each line in to the relevant text sections, e.g. trying to follow something like this SO question. But have hit mental block on how to get the relevant matching string sections for Year, Make and Model.
So far I have found this, that finds everthing between the parentheses:
\(([^()]+)\)
But not sure how to then group the the values and split by the commas:
Any help greatly appreciated.
Regex to get them in groups:
\((\d+),\s+[']([\w\së]+)['],\s+[']([\w\s]+)[']\)[,]*
Make note there is problem about Citroën => You have to enter all the special symbols not within a-z, A-Z (like ë ü ÿ etc..)
To use in code, You will get the groups 1st:
string cars = #"(1909, 'Ford', 'Model T'),"
string pattern = #"\((\d+),\s+[']([\w\së]+)['],\s+[']([\w\s]+)[']\)[,]*";
var lResult = Regex.Match(cars, pattern);
if(lResult.Success)
foreach( var iGroup in lResult.Groups)
Console.WriteLine(iGroup);
In lResult.Groups You got the info about car, You have just output it to the file as You need.
C# 6.0:
Console.WriteLine($"new Vehicle() {{ Id = 1, Year = {lResults.Groups[1]}, Make = \"{lResults.Groups[2]}\", Model = \"{lResults.Groups[3]}\"}},");
Old syntax:
Console.WriteLine(#"new Vehicle() { Id = 1, Year = "+ lMatch.Groups[1]+", Make = "+ lMatch.Groups[2] + ", Model = "+ lMatch.Groups[3] + " },");
Once You get this automatized into for loops, You can add Id easily.
My example have in Groups[0] whole string, so this is why my indexing starting from 1 to 3.
As #Toto said, \w already includes \d, there is no need to write it then.
Why not use string.Split(',')? Would be faster than Regex and suits for you (first delete the last ',' of each line, of course.
if you are willing to use a parser framework (which is maybe a little bit of an overkill), you could use for example sprache. Example without proper error handling:
Parser<string> stringContent =
from open in Parse.Char('\'').Once()
from content in Parse.CharExcept('\'').Many().Text()
from close in Parse.Char('\'').Once()
select content;
Parser<string> numberContent = Parse.Digit.AtLeastOnce().Text();
Parser<string> element = stringContent.XOr(numberContent);
Parser<List<string>> elements =
from e in element.DelimitedBy(Parse.Char(',').Token())
select e.ToList();
Parser<List<string>> parser =
from open in Parse.Char('(').Once()
from content in elements
from close in Parse.Char(')').Once()
select content;
var input = new List<string> { "(1909, 'Ford', 'Model T')", "(1926, 'Chrysler', 'Imperial')", "(1948, 'Citroën', '2CV')" };
foreach (var line in input)
{
var parsed = parser.Parse(line);
var year = Int32.Parse(parsed[0]);
var make = parsed[1];
var model = parsed[2];
Console.WriteLine(">> " + year + " " + make + " " + model);
}
You can use this snippet based on named capture groups:
var cars = new List<string>() {
"(1909, 'Ford', 'Model T')",
"(1926, 'Chrysler', 'Imperial')",
"(1948, 'Citroën', '2CV')",
};
var regex = #"(?<Year>\d+).*?'(?<Brand>.*?)'.*?'(?<Model>.*?)'";
foreach (var car in cars)
{
var match = Regex.Match(car, regex);
if (match.Success)
{
Console.WriteLine($"{match.Groups["Brand"]} make {match.Groups["Model"]} in {match.Groups["Year"]}");
}
}
Which will print:
Ford make Model T in 1909
Chrysler make Imperial in 1926
Citroën make 2CV in 1948
I'm trying to generate Item IDs using StreamReader on my .CSV file (It has to be a .csv file). The Item ID should start at 1000 and go up (1001, 1002, etc.)
Right now, if the user presses "Generate ID", it will search the entire file for the value "1000", if it doesn't exist, it will write "1000" in the textbox.
Here's what I need help with: If the file contains "1000", I want it to read the LAST line, increase it by 1, then write the value in the textbox.. So, if my last value is 1005 in the .csv file, I want it to write 1006 in the textbox.
private void GenerateID_Click(object sender, EventArgs e)
{
try
{
string searchString = "1000";
using (StreamReader sr = new StreamReader("file.csv"))
{
string line;
while ((line = sr.ReadLine()) != null)
{
if (line.Contains(searchString))
{
/* If file contains 1000, read the LAST line
* (Whatever number that may be: 1001, 1002, 1003, etc.)
* and increase that number by 1, then write to textbox. */
}
else
{
invItemIDField.Text = Convert.ToString("1000");
}
}
}
}
catch (Exception)
{
MessageBox.Show("The file could not be read");
}
}
I suggest you use FileHelpers. It's the most suitable library for reading CSV files.
To install this, you need to install first NuGet. Once installed, go to Tools > Library Package Manager > Package Manager Console:
Then, type in: Install-Package Filehelpers
You're good to go!
Import FileHelpers to your code
using FileHelpers;
Create a class that describes the structure of your CSV:
DelimitedRecord("'")]
public class MyCsv
{
public int Column1; // Your ID column
public string SomeOtherColumn;
}
Create a List<MyCsv>:
List<MyCsv> myList;
Then, to load your CSV:
FileHelperEngine<MyCsv> engine = new FileHelperEngine<MyCsv>();
myList = new List<MyCsv>(engine.ReadFile("my.csv")); // replace with your filename or variable containing the filename
You can now read your CSV by accessing the list myList:
foreach(MyCsv line in myList) {
// Do something;
}
Each object inside that list corresponds to each row in your CSV. In order to access the first column of a row (given the foreach loop above):
line.Column1
So, if you need to compare values, you can either use LINQ or do the traditional loop-search:
foreach(MyCsv line in myList) {
if (txtId.Text == line.Column1.ToString()) {
found = true;
break;
}
}
Then, to get the id of the last row:
myList.[myList.Count - 1].Column1
You can do the rest. Cheers!
Here's my go at it, it's slighlty different from yours, but it works. Granted there are things you must consider, such as are the elements surrounded in quotes, are the line breaks \r\n, and the like:
int TextBoxValue = 1000;
var reader = new StreamReader(File.OpenRead(#"C:\Users\J\Desktop\New Text Document (4).txt"));
var contents = reader.ReadToEnd().Split(new string[] {"\r\n"}, StringSplitOptions.None);
var iValueExists = (from String sLine in contents
where sLine.Contains("1000")
select sLine).Count();
if (iValueExists > 0)
{
TextBoxValue = int.Parse(contents.Last().Split(new string[] {","}, StringSplitOptions.None).First()) + 1;
}
invItemIDField.Text = TextBoxValue;
reader.Close();