Adding Payout to User using TextFile - c#

I'm having problems adding a payout amount to a user in a text file. Here's my current code:
public string payout = 1;
public static void AddPayout(int tPayout, string nickx) {
if (UserIsSub(nickx)) {
tPayout = payout * 2;
File.WriteAllLines("loyalty.txt", File.ReadAllLines("loyalty.txt")
.Select(x => {
if (x.StartsWith(nickx)) return nickx + " " + tPayout + "\n\r";
return x;
}));
} else {
tPayout = payout + 1;
File.WriteAllLines("loyalty.txt", File.ReadAllLines("loyalty.txt")
.Select(x => {
if (x.StartsWith(nickx)) return nickx + " " + tPayout + "\n\r";
return x;
}));
}
}
public static bool UserIsSub(String value)
{
if (File.ReadAllLines("subscribers.txt").Contains(value.ToLower())) { return true; }
else { return false; }
}
So far it just adds the same person, and keeps the number the same. What can I do the change that?

I guess you are using the wrong newline code,
try using \r\n instead of \n\r
(by the way, I dont think you need any newline sign, because writealllines should also write newlines)
then, you should insert a .ToArray after the select, because the file could be still open
then, you are replacing the line of code with the new amount. if you want to add the old one, you need to parse that line and replace the result.

Related

ArgumentOutOfRangeException: extracting string from string

I have a method that extracts a username from a string using conditionals to check common conventions, although it is resulting in an ArgumentOutOfRangeException on the GetPart utility method, even after explicitly checking before calling it?
Here is the extraction method
public bool TryExtractUsernameFromString(string str, out string username)
{
if (str.Contains("un: "))
{
username = GetPart(str, "un: ", " ");
}
else if (str.Contains("un:"))
{
username = str.Split(" ").Where(x => x.StartsWith("un:")).First().Substring(3);
}
else if (str.Contains("un- "))
{
username = str.IndexOf(" ", str.IndexOf("un- ") + 1) > 0 ? GetPart(str, "un- ", " ") : str[str.IndexOf("un- ")..str.Length];
}
else if (str.Contains("un-"))
{
username = str.Split(" ").Where(x => x.StartsWith("un-")).First().Substring(3);
}
else
{
username = "";
}
return username.Length > 0;
}
I am passing this as the first argument to TryExtractUsernameFromString (without quotes)
"😊un- jennyfromtheblock"
So it happens here,
else if (str.Contains("un- "))
{
username = str.IndexOf(" ", (str.IndexOf("un- ") + 1)) > 0 ? GetPart(str, "un- ", " ") : str[str.IndexOf("un -")..str.Length];
}
But shouldn't be calling GetPart() if it doesn't contain a second space after the first one in the str.Contains check.
GetPart method:
public static string GetPart(string s, string start, string end)
{
return s[(s.IndexOf(start) + start.Length)..s.IndexOf(end)];
}
str.IndexOf("un- ") + 1 is returning the index of the START + 1 of that substring. Try using str.IndexOf("un- ") + 4 instead. That'll get you the index of the second space you're looking for.
#DanRayson looks correct; But I wanted to add there is likely a much cleaner approach to this.
If statements can suck, case statements aren't really better. If you assume any name could have 0 or more matches:
public static void CleanName(string nameString, List<string> badPrefixes)
{
var matchedPrefixes = badPrefixes.Where(w => nameString.Contains(w)
&& && nameString.IndexOf(w) == 0).ToList();
foreach(var prefix in matchedPrefixes)
{
Console.WriteLine(nameString.Replace(prefix, "").Trim());
}
if (!matchedPrefixes.Any())
{
Console.WriteLine(nameString);
}
}
Another option would be using .FirstOrDefault instead of selecting all of the matches. But essentially, just find the match(es) and then remove it, and finally trim spaces.
Example
public static void Main()
{
List<string> badPrefixes = new List<string>()
{
"un:",
"un-",
"un ",
"Un", //Fun example too
};
string longUserName1 = "un- Austin";
string riskyLongName = "un: theUndying";
CleanName(longUserName1, badPrefixes);
// output: Austin
CleanName(riskyLongName, badPrefixes);
// output: theUndying
}

How to remove duplicate line results from textbox

Here is my data result code
it gets duplicate line results
I wanna remove duplicate result
Please help me
private void DataResult(string result, string acc, string file)
{
lock (this)
{
if (result == "good")
{
MetroTextBox metroTextBox = this.textBox1;
metroTextBox.Text = metroTextBox.Text + acc + Environment.NewLine;
file = Path.Combine(this.papka, "good.txt");
if (!Directory.Exists(this.papka))
{
Directory.CreateDirectory(this.papka);
}
File.AppendAllText(file, acc + "\r\n");
Listing.good++;
}
if (result == "error")
{
Listing.error++;
}
}
}
Add this to using directives at top of page:
using System.Linq;
Then simply use like so:
metroTextBox.Text = string.Join(Environment.NewLine, metroTextBox.Lines.Distinct());
In your example:
private void DataResult(string result, string acc, string file)
{
lock (this)
{
if (result == "good")
{
MetroTextBox metroTextBox = this.textBox1;
metroTextBox.Text = string.Join(metroTextBox.Lines.Distinct(), acc, Environment.NewLine);
file = Path.Combine(this.papka, "good.txt");
if (!Directory.Exists(this.papka))
{
Directory.CreateDirectory(this.papka);
}
File.AppendAllText(file, acc + "\r\n");
Listing.good++;
}
if (result == "error")
{
Listing.error++;
}
}
}
Assuming this method is the only way lines can get added to the text box, maybe you should check if the text box contains acc before you add it...
if(!metroTextBox.Text.Contains(acc))
metroTextBox.Text = metroTextBox.Text + acc + Environment.NewLine;
Side note; if you rename your text box on the form, you won't need to establish variables to it with other names. Click the text box on the form, and in the properties grid where it says (Name) textbox1, change that to metroTextBox
Side note 2; this code appends the contents of the text box to a file every time it adds a line to the text box. This could also be a source of duplication if the file name doesn't change because after adding 3 lines your file will look like:
line1
line1
line2
line1
line2
line3
I don't recommend you write a file as often as you add a line to a text box; one operation is trivial, the other is really slow and involved. Separate these things into different methods and call write file less often
You can try collecting unique results, with a help of HashSet<string>, e.g.
private HashSet<string> m_Results = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
then
private void DataResult(string result, string acc, string file)
{
lock (this)
{
if (result == "good")
{
if (m_Results.Add(result)) {
// result is unique (not in m_Results)
MetroTextBox metroTextBox = this.textBox1;
metroTextBox.Text = metroTextBox.Text + acc + Environment.NewLine;
file = Path.Combine(this.papka, "good.txt");
//DONE: no need to check for directoty exitance
Directory.CreateDirectory(this.papka);
File.AppendAllText(file, acc + "\r\n");
}
else {
// result has been appeared before
}
Listing.good++;
}
if (result == "error")
{
Listing.error++;
}
}
}

How to check if multiple checkboxes are checked

So in my program, i have three checboxes (A, B and C). and I want to save the content of the checkbox the is checked to a text file. I am doing this using if statements as shown below:
if (a.IsChecked == true)
{
res = a.Content.ToString() + " is checked";
}
else if (b.IsChecked == true)
{
res = b.Content.ToString() + " is checked";
}
else if (c.IsChecked == true)
{
res = c.Content.ToString() + " is checked";
}
And here is where i am saving the above values to a string and then later in my code to a text file
string test = res;
Now this is working for me. So i decided to try to check if multiple checkboxes are being checked. So added the below if statements:
else if ((a.IsChecked == true) && (b.IsChecked == true) && (c.IsChecked == true))
{
res= a.Content.ToString() + " " + b.Content.ToString() + " " + c.Content.ToString()
}
but this isn't working with me because in the end res is printed in the text file as a rather than a b c. Any idea what i am doing wrong?
Also please note that i already initialized res at the top of my code as string:
string res;
I am not getting any error when i run my code so i am not sure where my mistake is. any help with this is much much appreciated.
thanks a lot :)
Its a good practice to use a StringBuilder in these cases.
On the other hand, if it is ok to have one line for each CheckBox, you can use the following:
StringBuilder sb = new StringBuilder();
checkappend(ref sb, a);
checkappend(ref sb, b);
checkappend(ref sb, c);
string res = sb.ToString();
in which
static void checkappend(ref StringBuilder sb, CheckBox ck)
{
sb.Append(ck.Content.ToString());
sb.Append(ck.IsChecked == true ? "is checked." : " is NOT checked.");
sb.Append(Environment.NewLine);
}
Note that creating a separate class can help you when there are many CheckBoxes in a List. You can simply use
foreach (var ck in listOfCheckBoxes)
checkappend(ref ck, c);
You can implement it this way:
string res = "";
if (a.IsChecked)
{
res += a.Content.ToString();
}
if (b.IsChecked)
{
res += b.Content.ToString();
}
if (c.IsChecked)
{
res += c.Content.ToString();
}
or simple
string res = $"{(a.IsChecked?a.Content+" ":"")}{(b.IsChecked?b.Content+" ":"")}{(c.IsChecked?c.Content:"")}";
That's multiple combinations to check. Simply remove else from first code snippet to run all checks one after another. You will get only report from last successful check, to have several reports you have to accumulate them somehow (add to a list, combine in multi-line string, etc.).
Here is a simple one-liner (using linq):
var result = string.Join(" and ", new[] { a, b, c }.Where(o => o.IsChecked).Select(o => $"{o.Content} is checked"));

In file, if line contains substring, get all of the line from the right

I have a file. Each line looks like the following:
[00000] 0xD176234F81150469: foo
What I am attempting to do is, if a line contains a certain substring, I want to extract everything on the right of the substring found. For instance, if I were searching for 0xD176234F81150469: in the above line, it would return foo. Each string is of variable length. I am using C#.
As a note, every line in the file looks like the above, having a base-16 number enclosed in square brackets on the left, followed by a hexadecimal hash and a semicolon, and an english string afterwards.
How could I go about this?
Edit
Here is my code:
private void button1_Click(object sender, EventArgs e)
{
Form1 box = new Form1();
if(MessageBox.Show("This process may take a little while as we loop through all the books.", "Confirm?", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes)
{
XDocument doc = XDocument.Load(#"C:\Users\****\Desktop\books.xml");
var Titles = doc.Descendants("Title");
List<string> list = new List<string>();
foreach(var Title in Titles)
{
string searchstr = Title.Parent.Name.ToString();
string val = Title.Value;
string has = #"Gameplay/Excel/Books/" + searchstr + #":" + val;
ulong hash = FNV64.GetHash(has);
var hash2 = string.Format("0x{0:X}", hash);
list.Add(val + " (" + hash2 + ")");
// Sample output: "foo (0xD176234F81150469)"
}
string[] books = list.ToArray();
File.WriteAllLines(#"C:\Users\****\Desktop\books.txt", books);
}
else
{
MessageBox.Show("Aborted.", "Aborted");
}
}
I also iterated through every line of the file, adding it to a list<>. I must've accidentally deleted this when trying the suggestions. Also, I am very new to C#. The main thing I am getting stumped on is the matching.
You could use File.ReadLines and this Linq query:
string search = "0xD176234F81150469:";
IEnumerable<String> lines = File.ReadLines(path)
.Select(l => new { Line = l, Index = l.IndexOf(search) })
.Where(x => x.Index > -1)
.Select(x => x.Line.Substring(x.Index + search.Length));
foreach (var line in lines)
Console.WriteLine("Line: " + line);
This works if you don't want to use Linq query.
//"I also iterated through every line of the file, adding it to a list<>." Do this again.
List<string> li = new List<string>()
//However you create this string make sure you include the ":" at the end.
string searchStr = "0xD176234F81150469:";
private void button1_Click(object sender, EventArgs e)
{
foreach (string line in li)
{
string[] words;
words = line.Split(' '); //{"[00000]", "0xD176234F81150469:", "foo"}
if (temp[1] == searchStr)
{
list.Add(temp[2] + " (" + temp[1] + ")");
// Sample output: "foo (0xD176234F81150469)"
}
}
}
string file = ...
string search= ...
var result = File.ReadLines(file)
.Where(line => line.Contains(search))
.Select(line => line.Substring(
line.IndexOf(search) + search.Length + 1);
Unfortunately, none of the other solutions worked for me. I was iterating through the hashes using foreach, so I would be iterating through all the items millions of times needlessly. In the end, I did this:
using (StreamReader r = new StreamReader(#"C:\Users\****\Desktop\strings.txt"))
{
string line;
while ((line = r.ReadLine()) != null)
{
lines++;
if (lines >= 6)
{
string[] bits = line.Split(':');
if(string.IsNullOrWhiteSpace(line))
{
continue;
}
try
{
strlist.Add(bits[0].Substring(10), bits[1]);
}
catch (Exception)
{
continue;
}
}
}
}
foreach(var Title in Titles)
{
string searchstr = Title.Parent.Name.ToString();
string val = Title.Value;
string has = #"Gameplay/Excel/Books/" + searchstr + ":" + val;
ulong hash = FNV64.GetHash(has);
var hash2 = " " + string.Format("0x{0:X}", hash);
try
{
if (strlist.ContainsKey(hash2))
{
list.Add(strlist[hash2]);
}
}
catch (ArgumentOutOfRangeException)
{
continue;
}
}
This gave me the output I expected in a short period of time.

Create user-readable, display-friendly formatted string from List<string>

I know several questions have been asked and answered about how to create a comma delimited string from a list. I'm looking for help on something slightly different.
What I would like to do is create a display-friendly human-readable string from a List<string> that reads like "A, B and C are invalid values". The grammar and format of the string should change based on the number of items in the list. The list could contain any number of items.
For example:
List<string> myString = new List<string>() { "Scooby", "Dooby", "Doo" };
// Should return "Scooby, Dooby and Doo are invalid values."
List<string> myString = new List<string>() { "Scooby", "Dooby" };
// Should return "Scooby and Dooby are invalid values."
List<string> myString = new List<string>() { "Scooby" };
// Should return "Scooby is an invalid value."
Here's what I've done so far:
string userMessage = "";
foreach(string invalidValue in invalidValues)
{
userMessage = " " + userMessage + invalidValue + ",";
}
// Remove the trailing comma
userMessage = userMessage.Substring(0, userMessage.LastIndexOf(','));
if (invalidValues.Count > 1)
{
int lastCommaLocation = userMessage.LastIndexOf(',');
userMessage = userMessage.Substring(0, lastCommaLocation) + " and " + userMessage.Substring(lastCommaLocation + 1) + " are invalid values.";
}
else
{
userMessage = userMessage + " is an invalid value.";
}
Is there a better or more efficient way to do this?
public static string FormatList(List<string> invalidItems)
{
if(invalidItems.Count == 0) return string.Empty;
else if(invalidItems.Count == 1) return string.Format("{0} is an invalid value", invalidItems[0]);
else return string.Format("{0} and {1} are invalid values", string.Join(", ", invalidItems.Take(invalidItems.Count - 1)), invalidItems.Last());
}
Heavily indebted to #Lee in his other answer, here's a much-expanded version of his method. It allows you to specify a beginning text and/or an ending text, and it uses the Oxford comma, the omission of which, as we all know, once had catastrophic results for the plaintiff in a lawsuit... but if you hate the darn thing you can just remove it from the method as written.
public static string GrammaticallyCorrectStringFrom(List<string> items, string prefaceTextWithNoSpaceAtEnd, string endingTextWithoutPeriod)
{
var returnString = string.Empty;
if (items.Count != 0)
{
returnString = prefaceTextWithNoSpaceAtEnd + " ";
}
if (items.Count == 1)
{
returnString += string.Format("{0}", items[0]);
}
else if (items.Count == 2)
{
returnString += items[0] + " and " + items[1];
}
else if (items.Count > 2)
{
//remove the comma in the string.Format part if you're an anti-Oxford type
returnString += string.Format("{0}, and {1}", string.Join(", ", items.Take(items.Count - 1)), items.Last());
}
if (String.IsNullOrEmpty(returnString) == false)
{
returnString += endingTextWithoutPeriod + ".";
}
return returnString;
}
There's probably a better, less-verbose way to do the same thing, but this is working for me, and it's hard to argue with results. Actually I guess it isn't, here, but still... Anyway, anyone with a fire to improve this is welcome to.

Categories