C# RCon - Replace random amount of spaces? - c#

I currently got a problem with RCon.
I am basically sending a request to receive a list of all players.
The server answers with a list of all players like this:
# IP:Port Ping ID Name
0 127.0.0.1 0 3523523 Bob
12 192.168.0.1 120 342525523 Anna
320 192.168.0.2 240 63463634634 Chuck Norris
^^^ ^^ ^^^^^ ^
The problem is, I do not know how many spaces are between the different tags, it depends on how long the #/IP/ping and ID is.
The spaces can differ from 1 space to 5 spaces.
Also there can be spaces in the name so I can't just split with one space.
I want to read the IP, ping, id and name from the list.
I currently try to do some messy replace & split stuff but it just doesn't work out when the spaces are different.
I thought about doing something with regex but I am not so good with regex.
I already split the lines to cut it down to 1 line.
The class Player can store all the informations
Here is what should happen:
// List to store all the players
List<Player> players = new List<Player>();
// Using a StringReader to split up every line
StringReader reader = new StringReader(result);
string line;
int row = 0;
// Processing every line one after another
while ((line = reader.ReadLine()) != null)
{
row++;
// Doing some filtering to prevent empty lines and other stuff
if (row > 3 && !line.StartsWith("(") && line.Length > 0)
{
// Getting all the stuff I need here
// Then adding a player object to save the informations, ignore status
players.Add(new Player(ip, ping, id, name, status));
}
}
Anyone got an idea that could solve this?

I want to read the IP, ping, id and name from the list.
I very rarely say this but... this sounds like a job for regular expressions. If you're not good at them at the moment, use this as an opportunity to learn :)
Use a regular expression to match everything, capturing each value in a group, then fetch the groups afterwards.
Sample code:
using System;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
class Test
{
static void Main()
{
var regex = new Regex(#"^(?:\d+)\s+(?<ip>[\d.]+)\s+(?<ping>\d+)\s+(?<id>\d+)\s+(?<name>.*)$");
var query = File.ReadLines("data.txt")
.Skip(1)
.Select(line => regex.Match(line))
.Select(match => new {
IP = match.Groups["ip"].Value,
Ping = match.Groups["ping"].Value,
Id = match.Groups["id"].Value,
Name = match.Groups["name"].Value
});
foreach (var entry in query)
{
Console.WriteLine(entry);
}
}
}
Sample output:
{ IP = 127.0.0.1, Ping = 0, Id = 3523523, Name = Bob }
{ IP = 192.168.0.1, Ping = 120, Id = 342525523, Name = Anna }
{ IP = 192.168.0.2, Ping = 240, Id = 63463634634, Name = Chuck Norris }
Obviously you can parse the text for the ping, IP address etc. This was just to get you started. (Also, you should probably check for the success of the match...)

Simplest way would be to split your line into 5 parts
var items = line.Split(new char[] {' '}, 5, StringSplitOptions.RemoveEmptyEntries);
players.Add(new Player(items[1], items[2], items[3], items[4], "status?"));

Related

Splitting an element of an array

In my C# program (I'm new to C# so I hope that I'm doing things correctly), I'm trying to read in all of the lines from a text file, which will look something along the lines of this, but with more entries (these are fictional people so don't worry about privacy):
Logan Babbleton ID #: 0000011 108 Crest Circle Mr. Logan M. Babbleton
Pittsburgh PA 15668 SSN: XXX-XX-XXXX
Current Program(s): Bachelor of Science in Cybersecurity
Mr. Carter J. Bairn ID #: 0000012 21340 North Drive Mr. Carter Joseph Bairn
Pittsburgh PA 15668 SSN: XXX-XX-XXXX
Current Program(s): Bachelor of Science in Computer Science
I have these lines read into an array, concentrationArray and want to find the lines that contain the word "Current", split them at the "(s): " in "Program(s): " and print the words that follow. I've done this earlier in my program, but splitting at an ID instead, like this:
nameLine = nameIDLine.Split(new string[] { "ID" }, StringSplitOptions.None)[1];
However, whenever I attempt to do this, I get an error that my index is out of the bounds of my split array (not my concentrationArray). Here's what I currently have:
for (int i = 0; i < concentrationArray.Length; i++)
{
if (concentrationArray[i].Contains("Current"))
{
lstTest.Items.Add(concentrationArray[i].Split(new string[] { "(s): " }, StringSplitOptions.None)[1]);
}
}
Where I'm confused is that if I change the index to 0 instead of 1, it will print everything out perfectly, but it will print out the first half, instead of the second half, which is what I want. What am I doing wrong? Any feedback is greatly appreciated since I'm fairly new at C# and would love to learn what I can. Thanks!
Edit - The only thing that I could think of was that maybe sometimes there wasn't anything after the string that I used to separate each element, but when I checked my text file, I found that was not the case and there is always something following the string used to separate.
You should check the result of split before trying to read at index 1.
If your line doesn't contain a "(s): " your code will crash with the exception given
for (int i = 0; i < concentrationArray.Length; i++)
{
if (concentrationArray[i].Contains("Current"))
{
string[] result = concentrationArray[i].Split(new string[] { "(s): " }, StringSplitOptions.None);
if(result.Length > 1)
lstTest.Items.Add(result[1]);
else
Console.WriteLine($"Line {i} has no (s): followeed by a space");
}
}
To complete the answer, if you always use index 0 then there is no error because when no separator is present in the input string then the output is an array with a single element containing the whole unsplitted string
If the line will always starts with
Current Program(s):
then why don't you just replace it with empty string like this:
concentrationArray[i].Replace("Current Program(s): ", "")
It is perhaps a little easier to understand and more reusable if you separate the concerns. It will also be easier to test. An example might be...
var allLines = File.ReadLines(#"C:\your\file\path\data.txt");
var currentPrograms = ExtractCurrentPrograms(allLines);
if (currentPrograms.Any())
{
lstTest.Items.AddRange(currentPrograms);
}
...
private static IEnumerable<string> ExtractCurrentPrograms(IEnumerable<string> lines)
{
const string targetPhrase = "Current Program(s):";
foreach (var line in lines.Where(l => !string.IsNullOrWhiteSpace(l)))
{
var index = line.IndexOf(targetPhrase);
if (index >= 0)
{
var programIndex = index + targetPhrase.Length;
var text = line.Substring(programIndex).Trim();
if (!string.IsNullOrWhiteSpace(text))
{
yield return text;
}
}
}
}
Here is a bit different approach
List<string> test = new List<string>();
string pattern = "Current Program(s):";
string[] allLines = File.ReadAllLines(#"C:\Users\xyz\Source\demo.txt");
foreach (var line in allLines)
{
if (line.Contains(pattern))
{
test.Add(line.Substring(line.IndexOf(pattern) + pattern.Length));
}
}
or
string pattern = "Current Program(s):";
lstTest.Items.AddRange(File.ReadLines(#"C:\Users\ODuritsyn\Source\demo.xml")
.Where(line => line.Contains(pattern))
.Select(line => line.Substring(line.IndexOf(pattern) + pattern.Length)));

C# reading multiple lines into a single variable

I have looked but failed to find a tutorial that would address my question. Perhaps I didn't word my searches correctly. In any event, I am here.
I have taken over a handyman company and he had about 150 customers. He had a program that he bought that produces records for his customers. I have the records, but he wouldn't sell me the program as it is commercial and he's afraid of going to prison for selling something like that... whatever... They are written in a text file. The format appears to be:
string name
string last_job_description
int job_codes
string job_address
string comments
The text file looks like this
*Henderson*
*Cleaned gutters, fed the lawn, added mulch to the front flower beds,
cut the back yard, edged the side walk, pressure washed the driveway*
*04 34 32 1 18 99 32 22 43 72 11 18*
*123 Anywhere ave*
*Ms.always pays cash no tip. Mr. gives you a check but always tips*
Alright.. My question is in C# I want to write a program to edit these records, add new customers and delete some I may lose, moves, or dies... But the 2nd entry is broken over two lines, sometimes 3 and 4 lines. They all start and end with *. So, how do I read the 2 to 4 lines and get them into the last_job_description string variable? I can write the class, I can read lines, I can trim away the asterisks. I can find nothing on reading multiple lines into a single variable.
Let's do it right!
First define the customer model:
public class Customer
{
public string Name { get; set; }
public string LastJobDescription { get; set; }
public List<int> JobCodes { get; set; }
public string JobAddress { get; set; }
public string Comments { get; set; }
}
Then, we need a collection of customers:
var customers = new List<Customer>();
Fill the collection with data from the file:
string text = File.ReadAllText("customers.txt");
string pattern = #"(?<= ^ \*) .+? (?= \* \r? $)";
var options = RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled
| RegexOptions.Singleline | RegexOptions.Multiline;
var matches = Regex.Matches(text, pattern, options);
for (int i = 0; i < matches.Count; i += 5)
{
var customer = new Customer
{
Name = matches[i].Value,
LastJobDescription = matches[i + 1].Value,
JobCodes = matches[i + 2].Value.Split().Select(s => int.Parse(s)).ToList(),
JobAddress = matches[i + 3].Value,
Comments = matches[i + 4].Value
};
customers.Add(customer);
}
I'm using a regular expression that allows to have the * character in the middle of the lines.
Now we can comfortably work with this collection.
Examples of usage.
Remove the first customer:
customers.RemoveAt(0);
Add a comment to the latest client:
customers.Last().Comments += " Very generous.";
Find the first record for a client by the name of Henderson and add the code of the job performed:
customers.Find(c => c.Name == "Henderson").JobCodes.Add(42);
Add new customer:
var customer = new Customer
{
Name = "Chuck Norris",
LastJobDescription= "Saved the world.",
JobCodes = new List<int>() { 1 },
JobAddress = "UN",
Comments = "Nice guy!"
};
customers.Add(customer);
And so on.
To save data to a file, use the following:
var sb = new StringBuilder();
foreach (var customer in customers)
{
sb.Append('*').Append(customer.Name).Append('*').AppendLine();
sb.Append('*').Append(customer.LastJobDescription).Append('*').AppendLine();
sb.Append('*').Append(string.Join(" ", customer.JobCodes)).Append('*').AppendLine();
sb.Append('*').Append(customer.JobAddress).Append('*').AppendLine();
sb.Append('*').Append(customer.Comments).Append('*').AppendLine();
}
File.WriteAllText("customers.txt", sb.ToString());
You probably need a graphical user interface. If so, I suggest you to ask a new question where you specify what you use: WinForms, WPF, Web-application or something else.
if you want to read all the lines in a file into a single variable then you need to do this
var txt = File.ReadAllText(.. your file location here ..);
or you can do
var lines = File.ReadAllLines(.. your file location here); and then you can iterate through each line and remove the blanks of leave as it is.
But based on your question the first line is what you're really after
when you should read last_job_description read second line. if it starts with * it means that this line is job_codes otherwise append it to pervous read line. do this fo every lines until you find job_codes.
using (var fileReader = new StreamReader("someFile"))
{
// read some pervous data here
var last_job_description = fileReader.ReadLine();
var nextLine = fileReader.ReadLine();
while (nextLine.StartsWith("*") == false)
{
last_job_description += nextLine;
nextLine = fileReader.ReadLine();
}
//you have job_codes in nextline, so parse it now and read next data
}
or you may even use the fact that each set of data starts and ENDS!!! with * so you may create function that reads each "set" and returns it as singleline string, no matter how much lines it really was. let's assume that reader variable you pass to this function is the same StreamReader as in upper code
function string readSingleValue(StreamReader fileReader){
var result = "";
do
{
result += fileReader.ReadLine().Trim();
} while (result.EndsWith("*") == false);
return result;
}
I think your problem is little complex. What i am trying to say is it doesn't mention to a specific problem. It is contained at least 3 different programming aspects that you need to know or learn to reach your goal. The steps that you must take are described below.
unfortunately you need to consider your current file as huge string type.
Then you are able to process this string and separate different parts.
Next move is defining a neat, reliable and robust XML file which can hold your data.
Fill your xml with your manipulated string.
If you have a xml file you can simply update it.
There is not built-in method that will parse your file exactly like you want, so you have to get your hands dirty.
Here's an example of a working code for your specific case. I assumed you wanted your job_codes in an array since they're multiple integers separated by spaces.
Each time we encounter a line starting with '*', we increase a counter that'll tell us to work with the next of your properties (name, last job description, etc...).
Each line is appended to the current property.
And obviously, we remove the stars from the beginning and ending of every line.
string name = String.Empty;
string last_job_description = String.Empty;
int[] job_codes = null;
string job_address = String.Empty;
string comments = String.Empty;
int numberOfPropertiesRead = 0;
var lines = File.ReadAllLines("C:/yourfile.txt");
for (int i = 0; i < lines.Count(); i++)
{
var line = lines[i];
bool newProp = line.StartsWith("*");
bool endOfProp = line.EndsWith("*");
if (newProp)
{
numberOfPropertiesRead++;
line = line.Substring(1);
}
if (endOfProp)
line = line.Substring(0, line.Length - 1);
switch (numberOfPropertiesRead)
{
case 1: name += line; break;
case 2: last_job_description += line; break;
case 3:
job_codes = line.Split(' ').Select(el => Int32.Parse(el)).ToArray();
break;
case 4: job_address += line; break;
case 5: comments += line; break;
default:
throw new ArgumentException("Wow, that's too many properties dude.");
}
}
Console.WriteLine("name: " + name);
Console.WriteLine("last_job_description: " + last_job_description);
foreach (int job_code in job_codes)
Console.Write(job_code + " ");
Console.WriteLine();
Console.WriteLine("job_address: " + job_address);
Console.WriteLine("comments: " + comments);
Console.ReadLine();

read specific websourcecode in c#

When I press a button the following happens:
HttpWebRequest request = (HttpWebRequest)WebRequest
.Create("http://oldschool.runescape.com/slu");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader sr = new StreamReader(response.GetResponseStream());
richTextBox1.Text = sr.ReadToEnd();
sr.Close();
In short the data gets transferred to my textbox (this works perfectly)
Now if I choose world 78 (for example, from a combobox, it will refer to the last digits of that line) I want to get the value 968, if i choose world 14, I want to get the value 973.
This is an example of the printed data
e(378,true,0,"oldschool78",968,"United States","US","Old School 78");
e(314,true,0,"oldschool14",973,"United States","US","Old School 14");
What can I use to read this?
So there are two problems here, the first is selecting the right line, then getting the number out.
First you want a method for getting each of the lines in to a list, eg using something like this:
List<String> lines = new List<String>()
string line = sr.ReadLine();
while(line != null)
{
lines.Add(line);
line = sr.ReadLine(); // read the next line
}
Then you need to find the relevant line and get the token out of it.
Probably the most simple way is, for each line, split the string up by ',', '\"', '(' and ')' (using
String.Split). Ie, we get basically the parameters.
Eg
foreach(string lineInFile in lines)
{
// split the string in to tokens
string[] tokens = lineInFile.Split(',', '\"', '(', ')');
// based on the sample strings and how we've split this,
// we take the 15th entry
string endParameter = tokens[15]; //endParamter = "Old School 14"
...
We now use a regular expression to extract the number. The pattern we will use is d+, ie 1 or more digits.
Regex numberFinder = new Regex("\\d+");
Match numberMatch = numberFinder.Match(endParameter);
// we assume that there is a match, because if there isn't the string isn't
// correct, you should do some error handling here
string matchedNumber = numberMatch.Value;
int value = Int32.Parse(matchedValue); // we convert the string in to the number
if(value == desiredValue)
...
We check if the value matches the value we were looking for (eg 14), we now need to get the number you wanted.
We've already split the parameters, and the number we want is the 8th item (eg index 7 in string[] tokens). Since, at least in your example, this is just a lone number, we can just parse this to get the int.
{
return Int32.Parse(tokens[7]);
}
}
Again here we are assuming that the string is in the formats you showed, and you should do error protection here to.

c# how to put several groups of words from textfile into arrays

i have a textfile containing these kind of words
PEOPLE
John
0218753458
ENTERPRISE
stock
30%
HOME
Indiana
West Virginia
PEOPLE
Vahn
031245678
ENTERPRISE
Inc
50%
HOME
melbourne
Australia
i want to split these files into some strings that will divide the into each groups of PEOPLE, ENTERPRISE, and HOME. for example the output will be
part[0]
PEOPLE
John
0218753458
part[1]
ENTERPISE
stock
30%
part[2]
HOME
Indiana
West Virginia
and so on
i have a plan of using
EDIT #1 (thanks #Slade)
string[] part = s.Split(new string[] { "PEOPLE","ENTERPRISE","HOME" }, StringSplitOptions.None);
i can't change the structure.
is there any way to keep the HEADER? or better way to do this?
Don't use the || operator, that's for conditional/logical OR expressions. Instead, when filling elements of an array like you are doing, use a comma, like so:
string[] part = s.Split(new string[] { "PEOPLE", "ENTERPRISE", "HOME" }, StringSplitOptions.None);
However, unless you are always going to have these headings, it is not a good way of trying to split your text file. Instead, you need to define some structure to your file. For example, if you are always going to have headers in FULL CAPS, then you may want to start by splitting your text file into lines, then looping through each element and group the elements each time you hit a line containing only characters in FULL CAPS.
Personally, if possible, I would change the text file structure so you can flag headers with some symbol before or after: e.g. :THIS IS A HEADER. That way, you can split into lines then just look for the : symbol at the start of a line.
EDIT
For a sample approach on how to go about parsing this with the FULL CAPS headers, see my code example on PasteBin.
Note: The line ...
string[] lines = File.ReadAllLines(#"Sample.txt");
... could be replaced with ...
string textFromFile = File.ReadAllText(#"Sample.txt");
string[] lines = textFromFile.Split(new string[1] { System.Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
Using regex and because you want to keep the split strings in the results:
string[] tmp = Regex.Split(originalString, #"(PEOPLE|ENTERPRISE|HOME)");
List result = new List();
for(var i = 1; i < tmp.Count() - 1; i += 2) {
result.Add(tmp[i] + tmp[i+1]);
}
This gives you the result you want.
The reason why I'm concatenating the tmp array is because as of .NET 2.0, the Regex.Split will return the split strings as part of the array. I also start the indexing at 1 because we want our concatenation to happen late
s.Split(new string[] {"PEOPLE", "ENTERPRISE", ... }, StringSplitOptions.RemoveEmptyEntries);
And if you want save headers itself than possiblle it will be preferable to split your string multiple times by each arguments and add header by hands. For example you split your string by People and add people header to each chunk. Then split each chunk by HOME and add HOME header by hands and so on.
I'm going to give an answer that doesn't exactly match up with what you've asked for, so if you're dead set on having the output you've defined in your question then please disregard. Otherwise, I hope this is useful;
var peopleList = new List<string>();
var enterpriseList = new List<string>();
var homeList = new List<string>();
List<string> workingList = null;
using (var reader = new StreamReader("input.txt"))
{
string line = reader.ReadLine();
while (line != null)
{
switch (line)
{
case "PEOPLE": { workingList = peopleList; } break;
case "ENTERPRISE": { workingList = enterpriseList; } break;
case "HOME": { workingList = homeList; } break;
default: { workingList.Add(line); } break;
}
line = reader.ReadLine();
}
}
Based on your sample input, this will populate three lists as follows;
peopleList = { "John", "0218753458", "Vahn", "031245678" }
enterpriseList = { "stock", "30%", "Inc", "50%" }
homeList = { "Indiana", "West Virginia", "melbourne", "Australia" }

Searching for data in a console App!

using System;
using System.IO;
using System.Collections;
namespace ReadFiles
{
class Program
{
static void Main(string[] args)
{
StreamReader objstream = new StreamReader("c:\\documents and settings\\btallos\\desktop\\Company.txt");
string sLine ="";
ArrayList arrText = new ArrayList();
while (sLine != null)
{
sLine = objstream.ReadLine();
if (sLine != null)
arrText.Add(sLine);
}
objstream.Close();
foreach (string sOutput in arrText)
Console.WriteLine(sOutput);
Console.ReadLine();
}
}
}
I wrote a console app that displays information from a local file on my desktop and displays the content within the file. I was wondering how can I create a function that can search for keywords and only display the words, I want it to search for?
Can anyone help me out?
You should use the generic List instead of an ArrayList. You can then use the Where method and provide a string to search for, like this:
var lines = File.ReadAllLines("filename").ToList(); // Read all lines and cast it to a List<string>
var matches = lines.Where(x => x == "query");
foerach(var match in matches)
{
Console.WriteLine(match);
}
This will find all items equal to your query.
You can easily expand this to search for items containing your query by switching x => x == "query" to x => x.Contains("query")
I would start with File.ReadAllText and the push on to System.Text.RegularExpressions.Regex
Fuzzy requirements, but this is the solution from what I understood:
var keywords = new string[] {"some", "keywords"};
var foundKeywords = File.ReadAllLines("filename").
SelectMany(line => keywords.Where(keyword => line.Contains(keyword))).
Distinct();
The criteria can be improved (with a regular expression, for example). Currently it will also return you the keywords that are substrings of other words.
I'm going to try to put this content into a database - And then search for the content I want it to display.
* ZIP Codes
* Area Codes
* City Name
* State Name
* Two digit State Code
* City Type
* City Alias Abbrev.
* County Name
* State FIPS
* County FIPS
* Time Zone
* Daylight Savings Indicator
* Number of Businesses
* Q1 Payroll
* Annual Payroll
* Number of Employees
* Employment Flag
* County Growth Rate
You could figure out how you want to highlight the text you want to search in a console app (say be pre/postpending $$search text$$). Open each document and run a regex replace. If that returns a string length different than original, you have matches. If you don't want to show the whole document, I would get 50 characters before, and 50 after for example, but that might take a bit more work. Crude, but simple.

Categories