Read values from a textfile, delimited by = and $ signs - c#

how can i read from a text file , from a specific location for example i have a textfile
pathA = sometexthere$
pathB = sometexthere$
pathC = sometexthere$
TimerTC = sometexthere$
I want to read everything between "=" and "$"
To read line by line i'm using this:
int counter = 0;
string line;
System.IO.StreamReader file = new System.IO.StreamReader("config.cfg");
while((line = file.ReadLine()) != null)
{
if (counter == 1)
{
label1.Text=line;
counter++;
}
else if (counter == 2)
{
label2.Text=line;
counter++;
}
}

You can use SkipWhile and TakeWhile methods:
File.ReadLines("path")
.Select(line => new string(line
.SkipWhile(c => c != '=')
.Skip(1)
.TakeWhile(c => c != '$').ToArray())).ToList();

Solution 1:
int index;
List<string> listLines = new List<string>();
foreach (var line in File.ReadLines("C:\\Data.txt"))
{
index = line.LastIndexOf('=');
listLines.Add(line.Substring(index + 1, (line.Length - index) -
((line.Length) - line.LastIndexOf('$')+1)));
}
Solution2:
you can split every line with delimter = and then extract the word starting with = ending with $
string str;
List<string> listLines = new List<string>();
foreach (var line in File.ReadLines("C:\\Data.txt"))
{
str = line.Split('=')[1].Trim();
listLines.Add(str.Substring(0, str.Length -
(str.Length - str.LastIndexOf('$'))));
}
Solution 3:
List<string> listLines = new List<string>();
foreach (var line in File.ReadLines("C:\\Data.txt"))
{
var str = line.Split(new char[] { '=', '$'},
StringSplitOptions.RemoveEmptyEntries);
listLines.Add(str[1].Trim());
}

You can also do it using a Regex (although, now you have two problems):
var regex = new Regex(
#"^ # beginning of the line
(?<key>.*?) # part before the equals sign
\s*=\s* # `=` with optional whitespace
(?<value>.*) # part after the equals sign
\$ # `$`
$ # end of the line",
RegexOptions.Multiline |
RegexOptions.IgnorePatternWhitespace |
RegexOptions.Compiled);
Or, a one liner:
var regex = new Regex(#"^(?<key>.*?)\s*=\s*(?<value>.*)\$$");
And then select matches into key-value pairs:
var keyValuePairs = File
.ReadLines("config.cfg")
.Select(line => regex.Match(line))
.Where(match => match.Success)
.Select(match => new
{
Key = match.Groups["key"].Value,
Value = match.Groups["value"].Value
})
.ToList();

Related

Count occurence of a string in a list and display it in console

I'm creating a Logparser right now i'm able to go trought all the file in a folder line by line and extracting the substring i wanted which is the value after "fct=". All that using Regex and i put the result in a List.
Now i want to Count the occurence of every string in my list and display it.
I'm using GroupBy but when i display the result all the occurence are at 1.
Actual:
720 1x
720 1x
710 1x
And it should be:
720 2x
710 1x
I was able to find that the problem is that i read my file line by line so if the "fct=" value is not twice on the same line it won't count it a 2 but only at 1 for every line that its appears.
So i need to find a way to count my list and not my file line by line.
I'm really beginner so not sure how to do this any tips would be appreciated.
Here's the log data example:
<dat>FCT=10019,XN=KEY,CN=ROHWEPJQSKAUMDUC</dat></logurl>
<dat>XN=KEY,CN=RTU FCT=4515</dat>LBZ=test.sqi</logurl>
<dat>XN=KEY,CN=RT</dat>FCT=10019</logurl>
I want to display:
FCT=10019 2x
FCT=4515 1x
My Code:
class Program
{
static void Main(string[] args)
{
int counter = 0;
string[] dirs = Directory.GetFiles(#"C:/LogParser/LogParserV1", "*.txt");
StreamWriter sw = new StreamWriter("C:/LogParser/LogParserV1/test.txt");
char[] delimiters = { '<', ',', '&', ':', ' ', '\\', '\'' };
string patternfct = "(?<=FCT=)[0-9]*";
foreach (string fileName in dirs)
{
StreamReader sr = new StreamReader(fileName);
{
String lineRead;
while ((lineRead = sr.ReadLine()) != null)
{
//To find all the value of fct= occurence
var listfct = Regex.Matches(lineRead, patternfct,
RegexOptions.IgnoreCase).Cast<Match>().Select(x => x.Value).ToList();
var fctGroups = listfct.GroupBy(i => i);
foreach (var grp in fctGroups)
{
var fct = grp.Key;
var total = grp.Count();
System.Console.WriteLine("fct=" + fct + " " + "Total=" + total);
}
counter++;
}
System.Console.WriteLine(fileName);
sr.Close();
sw.Close();
}
}
// Suspend the screen.
System.Console.ReadLine();
}
}
}
You can try querying data with a help of Linq:
using System.Linq;
using System.Text.RegularExpressions;
...
Regex regex = new Regex("(?<=FCT=)[0-9]*", RegexOptions.IgnoreCase);
var records = Directory
.EnumerateFiles(#"C:/LogParser/LogParserV1", "*.txt")
.SelectMany(file => File.ReadLines(file))
.SelectMany(line => regex
.Matches(line)
.Cast<Match>()
.Select(match => match.Value))
.GroupBy(number => number)
.Select(group => $"FCT={group.Key} {group.Count()}x");
foreach (string record in records)
Console.WriteLine(record);
Demo: We can't mimic directory and files, so I've removed
Directory
.EnumerateFiles(#"C:/LogParser/LogParserV1", "*.txt")
.SelectMany(file => File.ReadLines(file))
but added testLines
string[] testLines = new string[] {
"<dat>FCT=10019,XN=KEY,CN=ROHWEPJQSKAUMDUC</dat></logurl>",
"<dat>XN=KEY,CN=RTU FCT=4515</dat>LBZ=test.sqi</logurl>",
"<dat>XN=KEY,CN=RT</dat>FCT=10019</logurl>",
};
Regex regex = new Regex("(?<=FCT=)[0-9]*", RegexOptions.IgnoreCase);
var records = testLines
.SelectMany(line => regex
.Matches(line)
.Cast<Match>()
.Select(match => match.Value))
.GroupBy(number => number)
.Select(group => $"FCT={group.Key} {group.Count()}x");
foreach (string record in records)
Console.WriteLine(record);
Outcome:
FCT=10019 2x
FCT=4515 1x
Edit: If you want to include file into records, you can use anonymous objects:
var records = Directory
.EnumerateFiles(#"C:/LogParser/LogParserV1", "*.txt")
.SelectMany(file => File
.ReadLines(file)
.Select(line => new {
file = file,
line = line,
}))
.SelectMany(item => regex
.Matches(item.line)
.Cast<Match>()
.Select(match => new {
file = item.file,
number = match.Value
}))
.GroupBy(item => new {
file = item.file,
number = item.number
})
.OrderBy(group => group.Key.file)
.ThenBy(group => group.Key.number)
.Select(group => $"{group.Key.file} has FCT={group.Key.number} {group.Count()}x")

How to separate sting with comma plus 8 digits

I want to split a long string (that contains only numbers) to string arr 0f numbers with 8 digits after the comma.
for example:
input:
string str = "45.00019821162.206580920.032150970.03215097244.0031982274.245303020.014716900.046867870.000198351974.613444580.391664580.438532450.00020199 3499.19734739 0.706802871.145335320.000202002543.362378010.513759201.659094520.000202102.391733720.000483371.65957789"
output:
string[] Arr=
"
45.00019821 162.20658092 234.03215097 123123.03215097
255.00019822 74.24530302 23422.01471690 1.04686787
12.00019835 1974.61344458 234.39166458 123212.43853245
532.00020199 3499.19734739 878.70680287 1.14533532
1234.00020200 2543.36237801 23.51375920 1.65909452
12221.00020210 2.39173372 0.00048337 1.65957789"
EDIT:
I try use
String.Format("{0:0.00000000}", str);
or some SubString such as:
public static string GetSubstring(string input, int count, char delimiter)
{
return string.Join(delimiter.ToString(), input.Split(delimiter).Take(count));
}
with no success.
You can split the string using Regex:
var strRegex = #"(?<num>\d+\.\d{8})";
var myRegex = new Regex(strRegex, RegexOptions.None);
foreach (Match myMatch in myRegex.Matches(str))
{
var part = myMatch.Groups["num"].Value;
// convert 'part' to double and store it wherever you want...
}
More compact version:
var myRegex = new Regex(#"(?<num>\d*\.\d{8})", RegexOptions.None);
var myNumbers = myRegex.Matches(str).Cast<Match>()
.Select(m => m.Groups["num"].Value)
.Select(v => Convert.ToDouble(v, CultureInfo.InvariantCulture));
The input string str can be converted to the desired output as follows.
static IEnumerable<string> NumberParts(string iString)
{
IEnumerable<char> iSeq = iString;
while (iSeq.Count() > 0)
{
var Result = new String(iSeq.TakeWhile(Char.IsDigit).ToArray());
iSeq = iSeq.SkipWhile(Char.IsDigit);
Result += new String(iSeq.Take(1).ToArray());
iSeq = iSeq.Skip(1);
Result += new String(iSeq.Take(8).ToArray());
iSeq = iSeq.Skip(8);
yield return Result;
}
}
The parsing method above can be called as follows.
var Parts = NumberParts(str).ToArray();
var Result = String.Join(" ", Parts);
This would be the classical for-loop version of it, (no magic involved):
// split by separator
string[] allparts = str.Split('.');
// Container for the resulting numbers
List<string> numbers = new List<string>();
// Handle the first number separately
string start = allparts[0];
string decimalPart ="";
for (int i = 1; i < allparts.Length; i++)
{
decimalPart = allparts[i].Substring(0, 8);
numbers.Add(start + "." + decimalPart);
// overwrite the start with the next number
start = allparts[i].Substring(8, allparts[i].Length - 8);
}
EDIT:
Here would be a LINQ Version yielding the same result:
// split by separator
string[] allparts = str.Split('.');
IEnumerable<string> allInteger = allparts.Select(x => x.Length > 8 ? x.Substring(8, x.Length - 8) : x);
IEnumerable<string> allDecimals = allparts.Skip(1).Select(x => x.Substring(0,8));
string [] allWholeNumbers = allInteger.Zip(allDecimals, (i, d) => i + "." + d).ToArray();
The shortest way without regex:
var splitted = ("00000000" + str.Replace(" ", "")).Split('.');
var result = splitted
.Zip(splitted.Skip(1), (f, s) =>
string.Concat(f.Skip(8).Concat(".").Concat(s.Take(8))))
.ToList()
Try it online!

update specific lines in text file C#

I'm trying to update specific lines in text file using this condition:
if line contain Word-to-search remove only the next space
using the blew code :
using (System.IO.TextReader tr = File.OpenText((#"d:\\My File3.log")))
{
string line;
while ((line = tr.ReadLine()) != null)
{
string[] items = line.Trim().Split(' ');
foreach (var s in items)
{
if (s == "a" || s == "b")
s = s.Replace(" ", "");
using (StreamWriter tw = new StreamWriter(#"d:\\My File3.log"))
tw.WriteLine(s);
my file is llike :
k l m
x y z a c
b d a w
the update file shold be like :
k l m
x y z ac
bd aw
I think you can do it by:
...
if (s == "a" || s == "b"){
if (s == "a")
s = s.Replace("a ", "a");
if (s == "b")
s = s.Replace("b ", "b");
using (StreamWriter tw = new StreamWriter(#"d:\\My File3.log"))
tw.WriteLine(s);
}
...
SAMPLE:
string test="a c";
test =test.Replace("a ", "a");
Console.WriteLine(test);
OUTPUT:
ac
try this:
....
while ((line = tr.ReadLine()) != null)
{
using (StreamWriter tw = new StreamWriter(#"d:\\My File3.log"))
string st = line.Replace("a ", "a").Replace("b ", "b");//just add additional .Replace() here
tw.WriteLine(st);
}
Your problem, I think, is here:
if (s == "a" || s == "b")
s = s.Replace(" ", "");
In order to satisfy your if condition, string s is necessarily without any spaces in it. Your code, therefore, does nothing.
if(s == "a" || s == "b")
foreach(var s2 in items)
{
if(items.IndexOf(s2) > items.IndexOf(s) && s2 == " ")
s2 == string.Empty;
break;
}
The break exists to ensure we only replace the next space, not all spaces following the character.
Are you looking for String.Replace?
string path = #"d:\My File3.log";
var data = File
.ReadLines(path)
.Select(line => line
.Replace("a ", "a")
.Replace("b ", "b"))
.ToList(); // Materialization, since we have to write back to the same file
File.WriteAllLines(path, data);
In general case, e.g.
if line contain Word-to-search
means that a and b should be words (b within abc is not the word we are looking for):
"abc a b c a" -> "abc abc a"
try using regular expressions:
string[] words = new string[] { "a", "b" };
string pattern =
#"\b(" + string.Join("|",
words.Select(item => Regex.Escape(item))) +
#")\s";
var data = File
.ReadLines(path)
.Select(line => Regex.Replace(line, pattern, m => m.Groups[1].Value))
.ToList();
File.WriteAllLines(path, data);
you should consider a temporary variable just before foreach loop
int temp = 0;
foreach(var s in items)
{
if (temp == 0)
{
if (s == "a" || s == "b")
{
temp = 1;
}
}
else
{
s = s.Replace(" ", "");
using (StreamWriter tw = new StreamWriter(#"d:\\My File3.log"))
tw.WriteLine(s);
temp = 0;
}
}
You cannot read and write at the same iteration to the same file.
Here a solution using StringBuilder (with him you can manipulate chars in the string):
using (StreamWriter tw = new StreamWriter(#"file1.txt"))
{
using (System.IO.TextReader tr = File.OpenText((#"file.txt")))
{
string line;
StringBuilder items = new StringBuilder();
while ((line = tr.ReadLine()) != null)
{
items.Append(line);
items.Replace("a ", "a");
items.Replace("b ", "b");
tw.WriteLine(items);
items.Clear();
}
}
}

How to find largest word that starts with a capital and add a separator and space

I have code that finds largest word that starts with a capital letter. But I need that word to add a separator and space. Any ideas how I should do it properly?
char[] skyrikliai = { ' ', '.', ',', '!', '?', ':', ';', '(', ')', '\t' };
string eilute = "Arvydas (g. 1964 m. gruodzio 19 d. Kaune)– Lietuvos, krepsininkas, olimpinis ir pasaulio cempionas, nuo 2011 m. spalio 24 d.";
static string Ilgiausias(string eilute, char[] skyrikliai)
{
string[] parts = eilute.Split(skyrikliai,
StringSplitOptions.RemoveEmptyEntries);
string ilgiaus = "";
foreach (string zodis in parts)
if ((zodis.Length > ilgiaus.Length) && (zodis[0].ToString() == zodis[0].ToString().ToUpper()))
ilgiaus = zodis;
return ilgiaus;
}
It should find word Lietuvos and add , and space
Result should be "Lietuvos, "
I would use LINQ for that:
var ilgiaus = parts.Where(s => s[0].IsUpper())
.OrderByDescending(s => s.Length)
.FirstOrDefault();
if(ilgiaus != null) {
return ilgiaus + ", ";
}
Also you can use regex and linq. You dont need to split by many characters.
Regex regex = new Regex(#"[A-Z]\w*");
string str = "Arvydas (g. 1964 m. gruodzio 19 d. Kaune)– Lietuvos, krepsininkas, olimpinis ir pasaulio cempionas, nuo 2011 m. spalio 24 d.";
string longest = regex.Matches(str).Cast<Match>().Select(match => match.Value).MaxBy(val => val.Length);
if you dont want to use MoreLinq, instead of MaxBy(val => val.Length) you can do OrderByDescending(x => x.Length).First()
There are probably more ingenious and elegant ways, but the following pseudocode should work:
List<String> listOfStrings = new List<String>();
// add some strings to the generic list
listOfStrings.Add("bla");
listOfStrings.Add("foo");
listOfStrings.Add("bar");
listOfStrings.Add("Rompecabeza");
listOfStrings.Add("Rumpelstiltskin");
. . .
String longestWorld = String.Empty;
. . .
longestWord = GetLongestCapitalizedWord(listOfStrings);
. . .
private String GetLongestCapitalizedWord(List<String> listOfStrings)
{
foreach (string s in listofstrings)
{
if ((IsCapitalized(s) && (s.Len > longestWord.Len)))
{
longestWord = s;
}
}
}
private bool IsCapitalized(String s)
{
return // true or false
}

how to split a string TWICE

I've been trying to split a string twice but I keep getting the error "Index was outside the bounds of the array".
This is the string I intend to split:
"a*b*c*d*e^1*2*3*4*5^e*f*g*h*i^"
such that I use the "^" as a delimiter in the first array separation so that each set will look as follows after the first result
a*b*c*d*e 1*2*3*4*5 e*f*g*h*i
Then thereafter perform another split operation on this set with * as the separator so that the results, for example from the first set is a b c d e
This is the C# code:
words = "a*b*c*d*e^1*2*3*4*5^e*f*g*h*i^";
char[] del = { '^' };
string[] splitResult = words.Split(del);
foreach (string w in splitResult)
{
char[] separator = { '*' };
string[] splitR = w.Split(separator);
foreach (string e in splitR)
{
string first = splitR[0];
string second = splitR[1];
string third = splitR[2];
string fourth = splitR[3];
string fifth = splitR[4];
}
}
To remove the last part where there is no result, how about
In C#
string str = "a*b*c*d*e^1*2*3*4*5^e*f*g*h*i^";
var result = str.Split(new char[] { '^' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Split('*')).ToArray();
In VB.Net
Dim str As String = "a*b*c*d*e^1*2*3*4*5^e*f*g*h*i^"
Dim result = str.Split(New Char() {"^"}, StringSplitOptions.RemoveEmptyEntries)
.Select(Function(x) x.Split("*")).ToArray()
You can do this with Linq:
IEnumerable<IEnumerable<string>> strings = words
.Split(new char[] { '^' }, StringSplitOptions.RemoveEmptyEntries)
.Select(w => w.Split('*'));
or if you prefer to work exclusively with arrays
string[][] strings = words
.Split(new char[] { '^' }, StringSplitOptions.RemoveEmptyEntries)
.Select(w => w.Split('*').ToArray())
.ToArray();
string words= "a*b*c*d*e^1*2*3*4*5^e*f*g*h*i^";
string[] reslts = words.Split(new char[] { '*', '^' }, StringSplitOptions.RemoveEmptyEntries);
You have a terminating separator, So the final string is empty.
If (w != null) {
string[] splitR = w.Split(separator);
If splitR.lenght > 4)
{
string first = splitR[0];
string second = splitR[1];
string third = splitR[2];
string fourth = splitR[3];
string fifth = splitR[4];
}
}
Try this:
string words = "a*b*c*d*e^1*2*3*4*5^e*f*g*h*i^";
char[] del = { '^' };
string[] splitResult = words.Split(del,StringSplitOptions.RemoveEmptyEntries);
foreach (string w in splitResult)
{
char[] separator = { '*' };
string[] splitR = w.Split(separator);
if(splitR.Length==5)
{
string first = splitR[0];
string second = splitR[1];
string third = splitR[2];
string fourth = splitR[3];
string fifth = splitR[4];
Console.WriteLine("{0},{1},{2},{3},{4}", first, second, third, fourth, fifth);
}
}
You are getting exception Index was outside the bounds of the array because in the last loop, it is getting only one item, I suggest you to check for five items:
words = "a*b*c*d*e^1*2*3*4*5^e*f*g*h*i^";
char[] del = { '^' };
string[] splitResult = words.Split(del);
foreach (string w in splitResult)
{
char[] separator = { '*' };
string[] splitR = w.Split(separator);
if (splitR.Length>=5)
{
foreach (string e in splitR)
{
string first = splitR[0];
string second = splitR[1];
string third = splitR[2];
string fourth = splitR[3];
string fifth = splitR[4];
}
}
}
One line does it all
var f = words.Split(new char[] { '^' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Split(new char[] { '*' }).ToArray())
.ToArray();
Your second loop does 5 times same thing (you don't use e).
The exception you got is because a last empty string was included resulting in an empty array that gave the index out of range exception in the inner loop.

Categories

Resources