I am trying to check if a text field is empty and I can't convert bool to string.
I am trying this:
var firstName = driver.FindElement(By.Id("name_3_firstname"));
if (firstName.Equals(" ")) {
Console.WriteLine("This field can not be empty");
}
Also, how can I check if certain number field is exactly 20 digits?
Can you help me do this?
Thank you in advance!
If it's string, then you can use string.Empty or "", because " " contains a space, therefore it's not empty.
For those 20 digits, you can use a bit of a workaround field.ToString().Length == 20 or you can repetitively divide it by 10 until the resulting value is 0, but I'd say the workaround might be easier to use.
This is more of a general C# answer. I'm not exactly sure how well it's gonna work in Selenium, but I've checked and string.Empty and ToString() appear to exist there.
For Empty / White space / Null, use following APIs of the string class
string.IsNullOrEmpty(value) or
string.IsNullOrWhiteSpace(value)
For exact 20 digits, best is to use the Regular expression as follows, this can also be converted to range and combination of digits and characters if required. Current regular expression ensures that beginning, end and all components are digits
string pattern = #"^\d{20}$";
var booleanResult = Regex.Match(value,pattern).Success
I'm not sure that this way will work in your case. Code:
var firstName = driver.FindElement(By.Id("name_3_firstname"));
will return to You IWebElement object. First you should try to get text of this element. Try something like firstName.Text or firstName.getAttribute("value");. When u will have this you will able to check
:
var text = firstName.getAttribute("value");
if(string.IsNullOrEmpty(text)){ // do something }
if(text.length == 20) {// do something}
I want to convert string to double.
Here's example of what I do :
string line = "4.1;4.0;4.0;3.8;4.0;4.3;4.2;4.0;";
double[] values = line2.Split(';').Select(double.Parse).ToArray();
But an error appears
Input string was not in a correct format.
When I try
string line2 = "1;2;3;4;5;6;7;8;9;10;11;12";
double[] values = line2.Split(';').Select(double.Parse).ToArray();
It works perfectly fine.
What should be input format for double values to work ?
Your problem is the last semicolon in the first input. The double.Parse method is being passed an empty string. double value2 = double.Parse(""); There are several ways to fix this, I'll outline two here:
Check if the last character in the input is a semicolon, if so, strip it. (This should be self explanatory.)
Use the StringSplitOptions.RemoveEmptyEntries overload.
I prefer the second option, myself. As this also removes issue with two consecutive semicolons.
string line = "4.1;4.0;4.0;3.8;4.0;;4.3;4.2;4.0;";
double[] values = line.Split(new char[]{';'}, StringSplitOptions.RemoveEmptyEntries).Select(double.Parse).ToArray();
Also, just to humour the idea that it could be a culture issue as well; the following code makes adjustments for culture-specific scenarios. The reason for the if check is to save on compute time. It could be removed if you desire, with no harm to the overall affect. (It simply means that the programme will replace . with . in situations where the programme is run on a computer with a culture set to use decimals for separators. This is merely a simple optimization.)
string line = "4.1;4.0;4.0;3.8;4.0;;4.3;4.2;4.0;";
if (CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator != ".")
line = line.Replace(".", CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);
double[] values = line.Split(new char[]{';'}, StringSplitOptions.RemoveEmptyEntries).Select(s => double.Parse(s)).ToArray();
Another sidebar about the potential for a culture issue: if it were a culture issue, the operation would not have thrown an exception, but instead simply return each digit of the number without separator. (I.e. 41, 40, 40, 38, 40, 43, 42, 40)
Other options:
Use double.TryParse instead.
Use a custom for loop and manually parse your data.
There are likely other options as well that I cannot think of.
Another option would be to use the double.TryParse() method on each item in your split array. This will ensure that each item in the array (empty or not) is a valid double before attempting to add it to the values array.
For example:
string line = "4.1;4.0;4.0;3.8;4.0;4.3;4.2;4.0;";
double temp = 0;
double[] values = line.Split(';')
.Where(item => double.TryParse(item, out temp))
.Select(i => temp).ToArray();
Basically our Problem is:
We can't replace a string like this: 10003*
But we can replace a string like this: 10003
we want to replace a part of a string that looks like this: 10003*
This is our Code:
string text = sr2.ReadToEnd();
sr2.Close();
while (loop != lstTxt.Items.Count)
{
string SelectedItem = lstTxt.SelectedItem.ToString() + "*";
text = text.Replace(SelectedItem, "tietze111");
if (lstTxt.SelectedIndex < lstTxt.Items.Count - 1)
lstTxt.SelectedIndex++;
loop++;
}
sw2.Write(text);
But it doesn't work. When we leave out the * in the part to replace, it works. But we have to replace the * too. Do you know what we have to change?
It works when we use this:
string text = sr2.ReadToEnd();
sr2.Close();
while (loop != lstTxt.Items.Count)
{
string SelectedItem = lstTxt.SelectedItem.ToString(); // changed
text = text.Replace(SelectedItem, "tietze111");
if (lstTxt.SelectedIndex < lstTxt.Items.Count - 1)
lstTxt.SelectedIndex++;
loop++;
}
sw2.Write(text);
--
using (var sr2 = new StreamReader(Application.StartupPath + #"\website\Dehler 22 ET.htm", Encoding.Default))
{
using (var sw2 = new StreamWriter(tempFile, true, Encoding.Default))
We are using this because the file is still in ASCII. Maybe that is the problem.
How do we solve this?
Fix the following line,
string SelectedItem = lstTxt.SelectedItem.Value;
You are taking the item and not the value.
Have you tried?
"[\*]"
Or
#"[*]"
The String.Replace(String,String) method doesn't do anything special with any characters. There is a character in your id that you are trying to replace is not the same as the one you are trying to match on. I would try copying the astrisk from the data source into your code and see if the problem still exists.
Your problem * is encoded in some other type. The Unicode value for asterisk U+002A
You could try this. Note Char.MinValue is technically a null value since you cannot have a blank Char.
In your case: lstTxt.SelectedItem.ToString() + '\u002A'.ToString();
If that doesn't work try removing (using different encoded values for *) to make sure you can actually find it in the string.
SomeString.Replace('\u002A', Char.MinValue);
OR
SomeString.Replace('\u002A'.ToString(), String.Empty);
I've ran into issues like this before and it ends up being a trial and error kind of thing until you get it right. Similar problem I had last summer C# String.Replace not finding / replacing Symbol (™, ®)
I've seen lots of samples in parsing CSV File. but this one is kind of annoying file...
so how do you parse this kind of CSV
"1",1/2/2010,"The sample ("adasdad") asdada","I was pooping in the door "Stinky", so I'll be damn","AK"
The best answer in most cases is probably #Jim Mischel's. TextFieldParser seems to be exactly what you want for most conventional cases -- though it strangely lives in the Microsoft.VisualBasic namespace! But this case isn't conventional.
The last time I ran into a variation on this issue where I needed something unconventional, I embarrassingly gave up on regexp'ing and bullheaded a char by char check. Sometimes, that's not-wrong enough to do. Splitting a string isn't as difficult a problem if you byte push.
So I rewrote for this case as a string extension. I think this is close.
Do note that, "I was pooping in the door "Stinky", so I'll be damn", is an especially nasty case. Without the *** STINKY CONDITION *** code, below, you'd get I was pooping in the door "Stinky as one value and so I'll be damn" as the other.
The only way to do better than that for any anonymous weird splitter/escape case would be to have some sort of algorithm to determine the "usual" number of columns in each row, and then check for, in this case, fixed length fields like your AK state entry or some other possible landmark as a sort of normalizing backstop for nonconformist columns. But that's serious crazy logic that likely isn't called for, as much fun as it'd be to code. As #Vash points out, you're better off following some standard and coding a little more OFfensively.
But the problem here is probably easier than that. The only lexically meaningful case is the one in your example -- ", -- double quote, comma, and then a space. So that's what the *** STINKY CONDITION *** code checks. Even so, this code is getting nastier than I'd like, which means you have ever stranger edge cases, like "This is also stinky," a f a b","Now what?" Heck, even "A,"B","C" doesn't work in this code right now, iirc, since I treat the begin and end chars as having been escape pre- and post-fixed. So we're largely back to #Vash's comment!
Apologies for all the brackets for one-line if statements, but I'm stuck in a StyleCop world right now. I'm not necessarily suggesting you use this -- that strictEscapeToSplitEvaluation plus the STINKY CONDITION makes this a little complex. But it's worth keeping in mind that a normal csv parser that's intelligent about quotes is significantly more straightforward to the point of being tedious, but otherwise trivial.
namespace YourFavoriteNamespace
{
using System;
using System.Collections.Generic;
using System.Text;
public static class Extensions
{
public static Queue<string> SplitSeeingQuotes(this string valToSplit, char splittingChar = ',', char escapeChar = '"',
bool strictEscapeToSplitEvaluation = true, bool captureEndingNull = false)
{
Queue<string> qReturn = new Queue<string>();
StringBuilder stringBuilder = new StringBuilder();
bool bInEscapeVal = false;
for (int i = 0; i < valToSplit.Length; i++)
{
if (!bInEscapeVal)
{
// Escape values must come immediately after a split.
// abc,"b,ca",cab has an escaped comma.
// abc,b"ca,c"ab does not.
if (escapeChar == valToSplit[i] && (!strictEscapeToSplitEvaluation || (i == 0 || (i != 0 && splittingChar == valToSplit[i - 1]))))
{
bInEscapeVal = true; // not capturing escapeChar as part of value; easy enough to change if need be.
}
else if (splittingChar == valToSplit[i])
{
qReturn.Enqueue(stringBuilder.ToString());
stringBuilder = new StringBuilder();
}
else
{
stringBuilder.Append(valToSplit[i]);
}
}
else
{
// Can't use switch b/c we're comparing to a variable, I believe.
if (escapeChar == valToSplit[i])
{
// Repeated escape always reduces to one escape char in this logic.
// So if you wanted "I'm ""double quote"" crazy!" to come out with
// the double double quotes, you're toast.
if (i + 1 < valToSplit.Length && escapeChar == valToSplit[i + 1])
{
i++;
stringBuilder.Append(escapeChar);
}
else if (!strictEscapeToSplitEvaluation)
{
bInEscapeVal = false;
}
// *** STINKY CONDITION ***
// Kinda defense, since only `", ` really makes sense.
else if ('"' == escapeChar && i + 2 < valToSplit.Length &&
valToSplit[i + 1] == ',' && valToSplit[i + 2] == ' ')
{
i = i+2;
stringBuilder.Append("\", ");
}
// *** EO STINKY CONDITION ***
else if (i+1 == valToSplit.Length || (i + 1 < valToSplit.Length && valToSplit[i + 1] == splittingChar))
{
bInEscapeVal = false;
}
else
{
stringBuilder.Append(escapeChar);
}
}
else
{
stringBuilder.Append(valToSplit[i]);
}
}
}
// NOTE: The `captureEndingNull` flag is not tested.
// Catch null final entry? "abc,cab,bca," could be four entries, with the last an empty string.
if ((captureEndingNull && splittingChar == valToSplit[valToSplit.Length-1]) || (stringBuilder.Length > 0))
{
qReturn.Enqueue(stringBuilder.ToString());
}
return qReturn;
}
}
}
Probably worth mentioning that the "answer" you gave yourself doesn't have the "Stinky" problem in its sample string. ;^)
[Understanding that we're three years after you asked,] I will say that your example isn't as insane as folks here make out. I can see wanting to treat escape characters (in this case, ") as escape characters only when they're the first value after the splitting character or, after finding an opening escape, stopping only if you find the escape character before a splitter; in this case, the splitter is obviously ,.
If the row of your csv is abc,bc"a,ca"b, I would expect that to mean we've got three values: abc, bc"a, and ca"b.
Same deal in your "The sample ("adasdad") asdada" column -- quotes that don't begin and end a cell value aren't escape characters and don't necessarily need doubling to maintain meaning. So I added a strictEscapeToSplitEvaluation flag here.
Enjoy. ;^)
I very strongly recommend using TextFieldParser. Hand-coded parsers that use String.Split or regular expressions almost invariably mishandle things like quoted fields that have embedded quotes or embedded separators.
I would be surprised, though, if it handled your particular example. As others have said, that line is, at best, ambiguous.
Split based on
",
I would use MyString.IndexOf("\","
And then substring the parts. Other then that im sure someone written a csv parser out there that can handle this :)
I found a way to parse this malformed CSV. I looked for a pattern and found it.... I first replace (",") with a character... like "¤" and then split it...
from this:
"Annoying","CSV File","poop#mypants.com",1999,01-20-2001,"oh,boy",01-20-2001,"yeah baby","yeah!"
to this:
"Annoying¤CSV File¤poop#mypants.com",1999,01-20-2001,"oh,boy",01-20-2001,"yeah baby¤yeah!"
then split it:
ArrayA[0]: "Annoying //this value will be trimmed by replace("\"","") same as the array[4]
ArrayA[1]: CSV File
ArrayA[2]: poop#mypants.com",1999,01-20-2001,"oh,boy",01-20-2001,"yeah baby
ArrayA[3]: yeah!"
after splitting it, I will replace strings from ArrayA[2] ", and ," with ¤ and then split it again
from this
ArrayA[2]: poop#mypants.com",1999,01-20-2001,"oh,boy",01-20-2001,"yeah baby
to this
ArrayA[2]: poop#mypants.com¤1999,01-20-2001¤oh,boy¤01-20-2001¤yeah baby
then split it again and would turn to this
ArrayB[0]: poop#mypants.com
ArrayB[1]: 1999,01-20-2001
ArrayB[2]: oh,boy
ArrayB[3]: 01-20-2001
ArrayB[4]: yeah baby
and lastly... I'll split the Year only and the date from ArrayB[1] with , to ArrayC
It's tedious but there's no other way to do it...
There is one another open source library, Cinchoo ETL, handle quoted string fine. Here is sample code.
string csv = #"""1"",1/2/2010,""The sample(""adasdad"") asdada"",""I was pooping in the door ""Stinky"", so I'll be damn"",""AK""";
using (var r = ChoCSVReader.LoadText(csv)
.QuoteAllFields()
)
{
foreach (var rec in r)
Console.WriteLine(rec.Dump());
}
Output:
[Count: 5]
Key: Column1 [Type: Int64]
Value: 1
Key: Column2 [Type: DateTime]
Value: 1/2/2010 12:00:00 AM
Key: Column3 [Type: String]
Value: The sample(adasdad) asdada
Key: Column4 [Type: String]
Value: I was pooping in the door Stinky, so I'll be damn
Key: Column5 [Type: String]
Value: AK
You could split the string by ",". It is recomended that the csv file could each cell value should be enclosed in quotes like "1","2","3".....
I don't see how you could if each line is different. This line is a malformed for CSV. Quotes contained within a value must be doubled as shown below. I can't even tell for sure where the values should be terminated.
"1",1/2/2010,"The sample (""adasdad"") asdada","I was pooping in the door ""Stinky"", so I'll be damn","AK"
Here's my code to parse a CSV file but I don't see how any code would know how to handle your line because it's malformed.
You might want to give CsvReader a try. It will handle quoted string fine, so you just will have to remove leading and trailing quotes.
It will fail if your strings contains a coma. To avoid this, the quotes needs to be doubled as said in other answers.
As no (decent) .csv parser can parse non-csv-data correctly, the task isn't to parse the data, but to fix the file(s) (and then to parse the correct data).
To fix the data you need a list of bad rows (to be sent to the person responsible for the garbage for manual editing). To get such a list, you can
use Access with a correct import specification to import the file. You'll get a list of import failures.
write a script/program that opens the file via the OLEDB text driver.
Sample file:
"Id","Remark","DateDue"
1,"This is good",20110413
2,"This is ""good""",20110414
3,"This is ""good"","bad",and "ugly",,20110415
4,"This is ""good""" again,20110415
Sample SQL/Result:
SELECT * FROM [badcsv01.csv]
Id Remark DateDue
1 This is good 4/13/2011
2 This is "good" 4/14/2011
3 This is "good", NULL
4 This is "good" again 4/15/2011
SELECT * FROM [badcsv01.csv] WHERE DateDue Is Null
Id Remark DateDue
3 This is "good", NULL
First you will do it for the columns names:
DataTable pbResults = new DataTable();
OracleDataAdapter oda = new OracleDataAdapter(cmd);
oda.Fill(pbResults);
StringBuilder sb1 = new StringBuilder();
StringBuilder sb2 = new StringBuilder();
IEnumerable<string> columnNames = pbResults.Columns.Cast<DataColumn>().Select(column => column.ColumnName);
sb1.Append(string.Join("\"" + "," + "\"", columnNames));
sb2.Append("\"");
sb2.Append(sb1);
sb2.AppendLine("\"");
Second you will do it for each row:
foreach (DataRow row in pbResults.Rows)
{
IEnumerable<string> fields = row.ItemArray.Select(field => field.ToString());
sb2.Append("\"");
sb2.Append(string.Join("\"" + "," + "\"", fields));
sb2.AppendLine("\"");
}
In the environment that my program is going to run, people use ',' and '.' as decimal separators randomly on PCs with ',' and '.' separators.
How would you implements such a floatparse(string) function?
I tried this one:
try
{
d = float.Parse(s);
}
catch
{
try
{
d = float.Parse(s.Replace(".", ","));
}
catch
{
d = float.Parse(s.Replace(",", "."));
}
}
It doesn't work. And when I debugg it turns out that it parses it wrong the first time thinking that "." is a separator for thousands (like 100.000.000,0).
I'm noob at C#, so hopefully there is less overcomplicated solution then that :-)
NB: People a going to use both '.' and ',' in PCs with different separator settings.
If you are sure nobody uses thousand-separators, you can Replace first:
string s = "1,23"; // or s = "1.23";
s = s.Replace(',', '.');
double d = double.Parse(s, CultureInfo.InvariantCulture);
The general pattern would be:
first try to sanitize and normalize. Like Replace(otherChar, myChar).
try to detect a format, maybe using RegEx, and use a targeted conversion. Like counting . and , to guess whether thousand separators are used.
try several formats in order, with TryParse. Do not use exceptions for this.
Parsing uses the settings of the CultureInfo.CurrentCulture, which reflects the language and the Number format selected by the user through Regional Settings. If your users type the decimals that correspond to the language they chose for their computers, you should have no problem using plain old double.Parse(). If a user sets his locale to Greek and types "8,5", double.Parse("8,5") will return 8.5. If he types "8.5" parse will return 85.
If a user sets his locale to one setting and then starts using the wrong decimal, you face a problem. There is no clean way to separate such wrong entries instead of entries that really wanted to enter the grouping character. What you can do is to warn the user when a number is too short to include a grouping character and use Masked or numerical text boxes to prevent wrong entries.
Another, somewhat stricter option, is to disallow the grouping character for number entry in your application by cancelling it in the KeyDown event of your textboxes. You can get the numeric and grouping characters from CultureInfo.CurrentCulture.NumberFormat property.
Trying to replace the decimal and grouping characters is doomed to fail as it depends on knowing during compile time what kind of separator the user is going to use. If you knew that, you could just parse the number using the CultureInfo in the user's mind. Unfortunately, User.Brain.CultureInfo is not yet part of the .NET framework :P
I would do someting like this
float ConvertToFloat(string value)
{
float result;
var converted = float.TryParse(value, out result);
if (converted) return result;
converted = float.TryParse(value.Replace(".", ",")),
out result);
if (converted) return result;
return float.NaN;
}
In this case the following would return correct data
Console.WriteLine(ConvertToFloat("10.10").ToString());
Console.WriteLine(ConvertToFloat("11,0").ToString());
Console.WriteLine(ConvertToFloat("12").ToString());
Console.WriteLine(ConvertToFloat("1 . 10").ToString());
Returns
10,1
11
12
NaN
In this case if it is not possible to convert it, you will at least know that it is not a number. It's a safe way to convert.
You can also use the following overload
float.TryParse(value,
NumberStyles.Currency,
CultureInfo.CurrentCulture,
out result)
On this test-code:
Console.WriteLine(ConvertToFloat("10,10").ToString());
Console.WriteLine(ConvertToFloat("11,0").ToString());
Console.WriteLine(ConvertToFloat("12").ToString());
Console.WriteLine(ConvertToFloat("1 . 10").ToString());
Console.WriteLine(ConvertToFloat("100.000,1").ToString());
It returns the following
10,1
11
12
110
100000,1
So depending on how "nice" you want to be to the user, you can always replace the last step, if it is not a number, try converting it this way aswell, otherwsie it really isn't a number.
It would the look like this
float ConvertToFloat(string value)
{
float result;
var converted = float.TryParse(value,
out result);
if (converted) return result;
converted = float.TryParse(value.Replace(".", ","),
out result);
if (converted) return result;
converted = float.TryParse(value,
NumberStyles.Currency,
CultureInfo.CurrentCulture,
out result);
return converted ? result : float.NaN;
}
Where the following
Console.WriteLine(ConvertToFloat("10,10").ToString());
Console.WriteLine(ConvertToFloat("11,0").ToString());
Console.WriteLine(ConvertToFloat("12").ToString());
Console.WriteLine(ConvertToFloat("1 . 10").ToString());
Console.WriteLine(ConvertToFloat("100.000,1").ToString());
Console.WriteLine(ConvertToFloat("asdf").ToString());
Returns
10,1
11
12
110
100000,1
NaN