im writing a basic program on c# for school and im having trouble with an if statement where the condition gets met but the code gets skipped as if the condition wasn't met.
//this runs when i select a cell on the dataGridView
private void dataGridView1_CellClick(object sender,DataGridViewCellEventArgs e)
{
string estado = "";
if (e.RowIndex >= 0)
{
DataGridViewRow row = this.dataGridView1.Rows[e.RowIndex];
id_lbl.Text = row.Cells[0].Value.ToString();
nombre_lbl.Text = row.Cells[1].Value.ToString();
apellido_lbl.Text = row.Cells[2].Value.ToString();
estado = row.Cells[7].Value.ToString();
}
id_lbl.Visible = true;
nombre_lbl.Visible = true;
apellido_lbl.Visible = true;
if(estado == "Activo")
{
baja_btn.Enabled = true;
}
else if (estado == "NoActivo")
{
alta_btn.Enabled = true;
}
else
{
MessageBox.Show(estado);
}
}
code runs but if statement jumps directly to else code and message box displays Activo, how ever, baja_btn.Enabled = true; does not run.
same is true if i select row with NoActivo. if jumps straight to else...
Note: the ACTUAL value of estado just before entering the if statement is Activo. so as it is it SHOULD go into the first condition but it skips all the way to else..
Two strings are not equal. To see where and why, let's try debug report (just before if):
...
String report = String.Format(
"Tested [{0}] encoded {1} of length {2}\r\nActual [{3}] encoded {4} of length {5}",
estado,
String.Join(" ", estado.Select(c => ((int) c).ToString("x4"))),
estado.Length,
"Activo", // <- copy/paste all "Activo" from the if
String.Join(" ", "Activo".Select(c => ((int) c).ToString("x4"))),
"Activo".Length);
MessageBox.Show(report);
if(estado == "Activo") // <- if of the question
...
Please, have a look at the report: where do you have differences? I've got two equal strings
Tested [Activo] encoded 0041 0063 0074 0069 0076 006f of length 6
Actual [Activo] encoded 0041 0063 0074 0069 0076 006f of length 6
but in your case there should be differences
EDIT: the experiment has shown that the tested value is
Tested [Activo ] 0041 0063 0074 0069 0076 006f 0020 0020 0020 0020 of lenght 10
So you have trailing spaces, it´s typical for many RDBMS: you have, say, CHAR(10) field in the table, and so you're given 10 character string. To solve the problem you can just trim the trailing spaces:
if (estado.TrimEnd() == "Activo")
{
baja_btn.Enabled = true;
}
Related
I need to check if a string contains only numbers(integers and decimal) with a space in between them.
Eg: 1 2 4.5 72 (this is acceptable);
1 7..5 3.2.1 (this is unacceptable)
You can use Double.TryParse() to verify if a string is a valid number, assuming integers and floats/doubles in this case. You will have to split the strings by whitespace beforehand using String.Split() to check each number individually. You can also utilize Enumerable.All<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>) from LINQ to check if all the strings satisfy a condition.
List<string> strings = new List<string> { "1 2 4.5 72", "1 7..5 3.2.1" };
foreach (string item in strings)
{
if (item.Split (new[] { " " }, StringSplitOptions.RemoveEmptyEntries).All (str => double.TryParse (str, out _)))
{
Console.WriteLine ($"{item} has only valid numbers.");
}
else
{
Console.WriteLine ($"{item} does have invalid numbers.");
}
}
// 1 2 4.5 72 has only valid numbers.
// 1 7..5 3.2.1 does have invalid numbers.
you can use split space first then check every split element numberic yes or not by decimal.TryParse + LINQ Any.
void Main()
{
Console.WriteLine( Check("1 2 4.5 72") ); //true
Console.WriteLine( Check("1 7..5 3.2.1") ); //false
}
bool Check(string text)
{
return text.Split(' ').Any(_ => decimal.TryParse(_, out var num) == false) == false;
}
I have a program that reads texts files and I'm wanting it to collect data after a certain title in the text file, in this case [HRData]. Once the streamreader reaches [HRData] I want it to read every line after that and store each line in a list, but allowing me to get access to the seperate numbers.
The text file is like so:
[HRZones]
190
175
162
152
143
133
0
0
0
0
0
[SwapTimes]
[Trip]
250
0
3978
309
313
229
504
651
//n header
[HRData]
91 154 70 309 83 6451
91 154 70 309 83 6451
92 160 75 309 87 5687
94 173 80 309 87 5687
96 187 87 309 95 4662
100 190 93 309 123 4407
101 192 97 309 141 4915
103 191 98 309 145 5429
So referring to the text file, I want it to store the first line after [HRData] and allow me access each variable, for example 91 being [0].
I have code that already stores to a list if the word matches the regex, but I do not know how to code it to read after a specific string like [HRData].
if (squareBrackets.Match(line).Success) {
titles.Add(line);
if (textAfterTitles.Match(line).Success) {
textaftertitles.Add(line);
}
}
This is my attempt so far:
if (line.Contains("[HRData]")) {
inttimes = true;
MessageBox.Show("HRDATA Found");
if (inttimes == true) {
while (null != (line = streamReader.ReadLine())) {
//ADD LINE AND BREAK UP INTO PARTS S
}
}
}
You can call a LINQ-friendly method File.ReadLines , then you can use LINQ to get the part you want:
List<string> numbers = File.ReadLines("data.txt")
.SkipWhile(line => line != "[HRData]")
.Skip(1)
.SelectMany(line => line.Split())
.ToList();
Console.WriteLine(numbers[0]); // 91
Edit - this will give you all the numbers in one List<string>, if you want to keep the line order, use Select instead of SelectMany:
List<List<string>> listsOfNums = File.ReadLines("data.txt")
.SkipWhile(line => line != "[HRData]")
.Skip(1)
.Select(line => line.Split().ToList())
.ToList();
Note that this requires additional index to get a single number:
Console.WriteLine(listsOfNums[0][0]); // 91
You could use a variable to track the current section:
var list = new List<int[]>();
using (StreamReader streamReader = ...)
{
string line;
string sectionName = null;
while (null != (line = streamReader.ReadLine()))
{
var sectionMatch = Regex.Match(line, #"\s*\[\s*(?<NAME>[^\]]+)\s*\]\s*");
if (sectionMatch.Success)
{
sectionName = sectionMatch.Groups["NAME"].Value;
}
else if (sectionName == "HRData")
{
// You can process lines inside the `HRData` section here.
// Getting the numbers in the line, and adding to the list, one array for each line.
var nums = Regex.Matches(line, #"\d+")
.Cast<Match>()
.Select(m => m.Value)
.Select(int.Parse)
.ToArray();
list.Add(nums);
}
}
}
Presuming your current code attempt works, which I have not gone through to verify...
You could simply do the following:
List<int> elements = new List<int>();
while (null != (line = streamReader.ReadLine()))
{
if(line.Contains("["))
{
//Prevent reading in the next section
break;
}
string[] split = line.Split(Convert.ToChar(" "));
//Each element in split will be each number on each line.
for(int i=0;i<split.Length;i++)
{
elements.Add(Convert.ToInt32(split[i]));
}
}
Alternatively, if you want a 2 dimensional list, such that you can reference the numbers by line, you could use a nested list. For each run of the outer loop, create a new list and add it to elements (elements would be List<List<int>>).
Edit
Just a note, be careful with the Convert.ToInt32() function. It should really be in a try catch statement just in case some text is read in that isn't numeric.
Edit
Ok.. to make the routine more robust (per my comment below):
First make sure the routine doesn't go beyond your block of numbers. I'm not sure what is beyond the block you listed, so that will be up to you, but it should take the following form:
If(line.Contains("[") || line.Contains("]") || etc etc etc)
{
break;
}
Next thing is pre-format your split values. Inside the for statement:
for(int i=0;i<split.Length;i++)
{
string val = split[i].Trim(); //Get rid of white space
val = val.Replace("\r\n",""); //Use one of these to trim every character.
val = val.Replace("\n","");
try
{
elements.Add(Convert.ToInt32());
}
catch (Exception ex)
{
string err = ex.Message;
//You might try formatting the split value even more here and retry convert
}
}
To access the individual numbers (presuming you are using a single dimension list) there are a couple ways to do this. If you want to access by index value:
elements.ElementAt(index)
if you want to iterate through the list of values:
foreach(int val in elements)
{
}
If you need to know exactly what line the value came from, I suggest a 2d list. It would be implemented as follows (I'm copying my code from the original code snippet, so assume all of the error checking is added!)
List<List<int>> elements = new List<List<int>>();
while (null != (line = streamReader.ReadLine()))
{
if(line.Contains("["))
{
//Prevent reading in the next section
break;
}
List<int> newLine = new List<int>();
string[] split = line.Split(Convert.ToChar(" "));
//Each element in split will be each number on each line.
for(int i=0;i<split.Length;i++)
{
newLine.Add(Convert.ToInt32(split[i]));
}
elements.Add(newLine);
}
Now to access each element by line:
foreach(var line in elements)
{
//line is a List<int>
int value = line.ElementAt(index); //grab element at index for the given line.
}
Alternatively, if you need to reference directly by line index, and column index
int value = elements.ElementAt(lineIndex).ElementAt(columnIndex);
Be careful with all of these direct index references. You could pretty easily get an index out of bounds issue.
One other thing.. you should probably put a breakpoint on your Convert.ToInt statement and find what string it is breaking on. If you can assume that the data input will be consistent, then finding exactly what string is breaking the conversion will help you create a routine that handles the particular characters that are filtering in. I am going to guess that the method broke when it attempted to Convert the last split value to an integer, and we had not removed line endings.
I use WinForms masked textbox to input time in the format of hh:mm:ss. My mask for this is 99:99:99, and I use right-to-left input mode.
The problem is, when I type 123 into it, I expect it to input 1:23, but it does this instead: __:12:3_ (so the value is 12:3x, and it replaces x with the next value that is typed).
What can I do to make it just push text to the left instead of copying the whole ss block to mm?
Edit: Here's a clarification:
My client needs to input time values in such a way that when he types:
12[Enter] it is accepted as 12 seconds
123[Enter] is 1 minute, 23 seconds
1234[Enter] would be 12 minutes, 34 seconds
12345[Enter] would be 1 hour, 23 minutes, 45 seconds, and so on...
The problem is that when 123 is typed into a masked textbox, it moves 12 to the minutes field, instead of just the 1, and only the 3 is left inside the seconds field.
Edit 2: As anyone who has worked with the masked textbox knows, setting the TextAlign to Right doesn't work the way you'd expect it to, like in any normal text editor. Instead, it just places the whole mask on the right side of the control, but the values are still inserted the same way as when the TextAligh is Left.
This is why I tried using RightToLeft.
What you want seems to be near impossible. How will the maskedtextbox know if you mean 1 digit to or 2 digits to apply to the first field that you type, unless you type the colon to show the separation?
I think for what you seem to want aDateTimePicker with a custom format of hh:mm:ss would work better. The input automatically starts at the hours field. The user can type 1 digit or 2 digits and then the colon and the input will automatically move to the next field. You also have the option of UpDown buttons that the user can click on to change the highlighted field.
By near impossible, I meant with native behavior. By creating a custom textbox that inherits from textbox you can do what you want:
public class TimeTextBox : TextBox
{
public TimeTextBox()
{
this.KeyPress += TimeTextBox_KeyPress;
}
public DateTime timeValue = new DateTime();
private void TimeTextBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
if(char.IsDigit(e.KeyChar))
{
Text += e.KeyChar;
SelectionStart = Text.Length;
}
else
{
MessageBox.Show("Wrong input");
return;
}
FixText();
if(Text.Length > 3 && !DateTime.TryParse(Text, out timeValue))
{
MessageBox.Show("Wrong input");
Text = Text.Remove(Text.Length - 1);
FixText();
timeValue = DateTime.Parse(Text);
}
}
private void FixText()
{
Text = Text.Replace(":", "");
for(int i = Text.Length - 3; i > -1; i -= 2)
{
Text = Text.Insert(i + 1, ":");
SelectionStart = Text.Length;
}
}
}
This will format and validate the input always counting from the right and inserting colons every 2 characters. There's simple validation, but it hasn't been tested for all scenarios.
You can use a simple text box and break the string as per this logic. I have only shown you for minutes and seconds you can extend it to hours following the code.
int seconds, minutes;
if (textBox1.Text.Length == 1 || textBox1.Text.Length == 2)
{
seconds = int.Parse(textBox1.Text);
}
else if (textBox1.Text.Length == 3)
{
seconds = int.Parse(textBox1.Text.Substring(1, 2));
minutes = int.Parse(textBox1.Text.Substring(0, 1));
}
else if (textbox1.Text.Length == 4)
{
seconds = int.Parse(textBox1.Text.Substring(2, 2));
minutes = int.Parse(textBox1.Text.Substring(0, 2));
}
I am working through Joyce Farrell's Visual C#2012 on my own (this is not a homework assignment). I have been stuck on this for the past two days, and have yet to find an answer that I understand. I am looking for a simple program - nothing fancy as I probably haven't read that chapter yet. :-) The problem that I am having is when I am trying to show '' for a non-guessed or incorrectly guessed letter. If I assign '' it looks good for the first letter, but when the user enters a second guess, it changes the second guess to a '?'. Why is that? Any help would be really appreciated. Thank you.
static void Main(string[] args)
{
string[] mysteryWordList = { "green", "snowflake", "tree", "joy", "red", "gift", "frozen", "merry" };
string mysteryWord; // hidden word
char[] mysteryWordArray;
char letterGuessed;
char[] guessWordArray;
Random ranNumberGenerator = new Random(); // generate a random number, at least 0 but < 8
int randomNumber = ranNumberGenerator.Next(0, 8);
mysteryWord = mysteryWordList[randomNumber]; // select a word from list using random number
Console.WriteLine("The Mystery word is: " + mysteryWord); // print word for my validation
mysteryWordArray = mysteryWord.ToArray(); // put mystery word into array to compare against guessWord array
Console.Write("MysterywordArray is: ");
Console.WriteLine(mysteryWordArray);
guessWordArray = new char[mysteryWord.Length]; // assign length to user guess array
// write mystery word in *'s
for (int x = 0; x < mysteryWord.Length; ++x)
Console.Write("*");
//guessWordArray[x] += '%'; adds value and then does not work...
Console.WriteLine();
while (guessWordArray != mysteryWordArray)
{
Console.Write("\nPlease guess a letter: ");
letterGuessed = Convert.ToChar(Console.ReadLine());
for (int x = 0; x < mysteryWord.Length; ++x)// go through each letter in mystery word
{
if (letterGuessed == mysteryWordArray[x]) // if match do this
{
Console.WriteLine("Yes, the letter {0} is in the mystery word!", letterGuessed);
guessWordArray[x] += letterGuessed;
}
if (letterGuessed != mysteryWordArray[x] && guessWordArray[x] == default(char)) // if match do this
guessWordArray[x] += '*';
}
Console.Write("Mystery Word: ");
Console.WriteLine(guessWordArray);
}
}
The command guessWordArray[x] += letterGuessed; is wrong. It dosent add the letter to the array it actualy changes the Xth element in the array. For example if guesswordArray contains { 'a', 'b', 'c' }
guesswordArray[0] += 'a' translates to guessWordArray[2] = 'a' + 'a'. Character addition is done by converting a character to the ascii code then the result is converted to a character. That means 'a'== 97 'a'+'a' == 194' Then 194 is converted back to a weird character from the ascii table.
This two lines :
guessWordArray[x] += letterGuessed;
....
guessWordArray[x] += '*';
should be like this instead :
guessWordArray[x] = letterGuessed;
....
guessWordArray[x] = '*';
By this += operator, you are appending the char from user input to existing char saved in the array. That will produce special character which which won't be displayed well in console (that's why you saw sort of ? char). I think you need to just assign the input char and replace existing char by using = instead of +=
Characters are essentially integers in their most basic form. When you are attempting to add subsequent letters to your array you are using += which is adding characters together. The initial character '*' is ASCII code 42, so what's happening is when you select a new letter ('g' for example in "gift") you are adding 103 to to that 42, and the ASCII character with the value 145 is being stored in the array. That value is unable to be displayed properly by the console. You need to just use the assignment operator since you want to write the new character to the array at the current index.
guessWordArray[x] = letterGuessed;
guessWordArray[x] = '*';
I want to add one space after every two characters, and add a character in front of every single character.
This is my code:
string str2;
str2 = str1.ToCharArray().Aggregate("", (result, c) => result += ((!string.IsNullOrEmpty(result) && (result.Length + 1) % 3 == 0) ? " " : "") + c.ToString());
I have no problems separating every two characters with one space, but how do I know if the separated string has an individual character, and add a character infront of that character?
I understand that my question is confusing as I'm not sure how to put what I want in words..
So I'll just give an example:
I have this string:
0123457
After separating every two characters with a space, I'll get:
01 23 45 7
I want to add a 6 infront of the 7.
Note: Numbers are dependent on user's input, so it's not always the same.
Thanks.
[TestMethod]
public void StackOverflowQuestion()
{
var input = "0123457";
var temp = Regex.Replace(input, #"(.{2})", "$1 ");
Assert.AreEqual("01 23 45 7", temp);
}
Try something like this:
static string ProcessString(string input)
{
StringBuilder buffer = new StringBuilder(input.Length*3/2);
for (int i=0; i<input.Length; i++)
{
if ((i>0) & (i%2==0))
buffer.Append(" ");
buffer.Append(input[i]);
}
return buffer.ToString();
}
Naturally you'd need to add in some logic about the extra numbers, but the basic idea should be clear from the above.
May be you can try, if i right understand your request,
String.Length % 2
if result is 0, you done with first iteration, if not, just add a character infront of last one.
I think this is what you asked for
string str1 = "3322356";
string str2;
str2 = String.Join(" ",
str1.ToCharArray().Aggregate("",
(result, c) => result += ((!string.IsNullOrEmpty(result) &&
(result.Length + 1) % 3 == 0) ? " " : "") + c.ToString())
.Split(' ').ToList().Select(
x => x.Length == 1
? String.Format("{0}{1}", Int32.Parse(x) - 1, x)
: x).ToArray());
result is "33 22 35 56"