i have a List box with some texts , i wanna get all the strings after Other:
and this is the code i use
string[] causearr = lst_Box.Items[i].Value.Split('-');
SqlSrcComplainCgeAnalysis.InsertParameters["ID"].DefaultValue =causearr[0].ToString(); SqlSrcComplainCgeAnalysis.InsertParameters["subId"].DefaultValue = causearr[2].ToString();
if (txt_OtherCause.Text != string.Empty && txt_OtherCause.Visible == true && (int.Parse(causearr[2].ToString()) == 7 || int.Parse(causearr[2].ToString()) == 15 || int.Parse(causearr[2].ToString()) == 21))
SqlSrcComplainCgeAnalysis.InsertParameters["CauseComments"].DefaultValue = causearr[3].ToString().Substring(causearr[3].ToString().LastIndexOf(":") + 3);
else
SqlSrcComplainCgeAnalysis.InsertParameters["CauseComments"].DefaultValue = string.Empty;
and this is the data in the List Box
Cause:SpareParts-SubCause:Others: First Line
Cause:Technical-SubCause:Others: Second Line
so how to return the data after "Others:" if this data changes , and also the Cause changes according to the user selection .
string s = "Cause:SpareParts-SubCause:Others: First Line".Split(new char[] { ' ' }, 2)[1];
string value = "Cause:SpareParts-SubCause:Others: First Line"
string[] lines = Regex.Split(value, ":Others:");
you now need lines[1] i guess
What you can do is split the string first on the colons ':', and then the last item in the array would be the data that you want.
result[0] == 'Cause'
result[1] == 'SpareParts-SubCause'
result[2] == 'Others'
result[4] == 'Cause'
result[5] == 'First Line'
or you could use a Regex to do all this in a cool way:
http://msdn.microsoft.com/en-us/library/hs600312.aspx
Related
I need to test for all values being only "0" or "1" in a string array and tried the following code without success:
bool isBool = Array.TrueForAll(str, val => val.Trim() == "0" || val.Trim() == "1");
and
bool isBool = str.All(val => val.Trim() == "0" || val.Trim() == "1");
Is there a different way I have to do this because I'm using a || condition?
I'm assuming that you mean the values have to be exclusively all 1's or 0's? In that case you need to test each case separately. Your existing code is true when the array contains only 0's or 1's. It would be false if any of the values were 2 though. One solution:
var allAreZero = new string[] { " 0 ", " 0", " 0" };
var allAreOne = new string[] { " 1 ", "1", " 1" };
var mixedOnesAndZeros = new string[] { " 1 ", "0", " 1" };
private bool ArrayIsExclusivelyTrueOrFalse(string[] data)
{
return data.All(i => int.TryParse(i, out int value) && value == 0) ||
data.All(i => int.TryParse(i, out int value) && value == 1);
}
ArrayIsExclusivelyTrueOrFalse(allAreZero); // true
ArrayIsExclusivelyTrueOrFalse(allAreOne); // true
ArrayIsExclusivelyTrueOrFalse(mixedOnesAndZeros); // false
Try this
var isBool = !str.Select(s => s.Trim()).Distinct().Any(s => s != "0" && s != "1");
you can try Any() and return in the first failing condition !str.Any(x => x.Trim() != "0" && x.Trim() != "1")
If you want to ensure that all the values in your array are either ALL "0" or ALL "1" (but not a mix of "0" and "1", as I originally read it), then one way would be to ensure that the number of Distinct items (after trimming) has a Count of 1 (meaning they're all the same), and that the item is a member of the set of valid values (in the code below we just check the first item, since we already know they're all the same at that point).
For example:
var validValues = new[] {"0", "1"};
var isBool = str.Select(i => i.Trim()).Distinct().Count() == 1 &&
validValues.Contains(str[0].Trim());
Is there any way to translate the following query
select word
from string1
where Left(word, 1) in (
select Left(word, 1) as firstInitial
from string1
group by Left(word , 1)
having count(*) > 1
)
into LINQ so when you run it on "While Kim kept kicking I ate my Dunkin donut with great gusto" it produces something like
(miss,Match,Match,Match,miss,miss,miss,Match,Match,miss,Match,Match)
The following solution shows one possible approach. To use this, be sure to add the MoreLINQ NuGet package to your project.
using System;
using System.Linq;
using MoreLinq;
namespace Test
{
class Program
{
static void Main(string[] args)
{
var input = "While Kim kept kicking I ate my Dunkin donut with great gusto";
var value = input.Split(' ');
var lagged = value.Lag(1, (current, previous) => new { current = current?.ToLowerInvariant(), previous = previous?.ToLowerInvariant() });
var leaded = value.Lead(1, (current, next) => new { next = next?.ToLowerInvariant() });
var results = lagged.Zip(leaded, (x, y) => x.current?.FirstOrDefault() == x.previous?.FirstOrDefault() ||
x.current?.FirstOrDefault() == y.next?.FirstOrDefault());
Console.WriteLine(string.Join(",", results));
Console.ReadLine();
}
}
}
Basically the code splits the string into multiple words, and then looks at each word (current) and the word before (previous) and after (next) it. It then compares the first letter of current vs that of previous and next.
If you want to return 1 / 0 rather than true / false then change just this line of code:
var results = lagged.Zip(leaded, (x, y) => (x.current?.FirstOrDefault() == x.previous?.FirstOrDefault() ||
x.current?.FirstOrDefault() == y.next?.FirstOrDefault()) ? 1 : 0);
The solution for this won't be as simple as a few lines, but I can try:
First, the simplest but not so elegant for loop method:
var words = string1.Split(' ').ToList();
string[] results = new string[words.Count]; //edited: can use .Count instead of .Count()
for (int i = 0; i < words.Count; i++)
{
if (i == words.Count - 1)
results[i] = char.ToLower(words[i - 1][0]) == char.ToLower(words[i][0]) ? "Match" : "miss";
else if (i == 0)
results[i] = char.ToLower(words[i + 1][0]) == char.ToLower(words[i][0]) ? "Match" : "miss";
else
{
bool leftMatch = char.ToLower(words[i - 1][0]) == char.ToLower(words[i][0]);
bool rightMatch = char.ToLower(words[i + 1][0]) == char.ToLower(words[i][0]);
results[i] = (leftMatch || rightMatch) ? "Match" : "miss";
}
}
What this does is go through each element, if the left or right word has a same initial character, it is a "Match", otherwise it is "miss". For the first and last word it just needs to check one neighbor instead of 2.
Using Enumerable.Range Method (Int32, Int32) of LINQ, as well as the ?: Operator, this can be simplified into a few lines:
var words = string1.Split(' ').ToList();
var results = Enumerable.Range(0, words.Count).Select(i => i == words.Count - 1 ?
char.ToLower(words[i - 1][0]) == char.ToLower(words[i][0]) ? "Match" : "miss" :
i == 0 ?
char.ToLower(words[i + 1][0]) == char.ToLower(words[i][0]) ? "Match" : "miss" :
(char.ToLower(words[i - 1][0]) == char.ToLower(words[i][0]) || char.ToLower(words[i + 1][0]) == char.ToLower(words[i][0])) ? "Match" : "miss" ).ToList();
The ToList() at the end is optional, you can convert ToArray() if you wish.
I have logic where customer specifies a string and my app tells to the customer if this string presents in the text, something like this:
internal const string GlobalText = "blablabla";
bool PresentInTheText(string searchString)
{
return GlobalText.IndexOf(searchString, StringComparison.OrdinalIgnoreCase) >= 0;
}
Basically if text contains passed string return true otherwise false.
Now I want to make it more complex. Lets say if customer passes a string "foo && bar", and I need to return true if this text contains both "foo" and "bar" substrings, straightforward approach:
bool result;
if (!string.IsNullOrEmpty(passedExpression) &&
passedExpression.Contains(" && "))
{
var tokens = passedExpression.Split(new[] { " && " }, StringSplitOptions.RemoveEmptyEntries);
result = true;
foreach (var token in tokens)
{
if (GlobalText.IndexOf(token, StringComparison.OrdinalIgnoreCase) < 0)
{
result = false;
}
}
}
return result;
It works for expressions like A && B && C. But I want generalize the solution to support all boolean operators.
Let's say: ("foo" && "bar") || "baz". What would be the solution?
I would say take passed string, using regex add to all strings .IndexOf(token, StringComparison.OrdinalIgnoreCase) < >= 0 code, it would be like this:
("foo".IndexOf(token, StringComparison.OrdinalIgnoreCase) < >= 0 &&
"bar".IndexOf(token, StringComparison.OrdinalIgnoreCase) < >= 0)) ||
"baz".IndexOf(token, StringComparison.OrdinalIgnoreCase) < >= 0
and then turn this string into a function and execute using Reflections. What would be the best solution?
ETA:
Test cases:
bool Contains(string text, string expressionString);
string text = "Customers: David, Danny, Mike, Luke. Car: BMW"
string str0 = "Luke"
string str1 = "(Danny || Jennifer) && (BMW)"
string str2 = "(Mike && BMW) || Volvo"
string str3 = "(Mike || David) && Ford"
string str4 = "David && !BMW"
bool Contains(string text, string str0); //True - This text contains "Luke"
bool Contains(string text, string str1); //True - David and BMW in the text
bool Contains(string text, string str2); //True - Mike and BMW in the text
bool Contains(string text, string str3); //False - no Ford in the list
bool Contains(string text, string str4); //False - BMW in the list
You can solve this universally in the same way that a calculator, or a compiler, evaluates an expression:
Tokenize the string and identify each token as an operator (OP) or an operand (A, B, C, etc).
Convert the token sequence from infix (A OP B) to postfix (A B OP).
Evaluate the postfix token sequence.
Each of these steps can be done with a well known stack based algorithm, in linear time and space. Plus, if you use this method, it automatically extends to any binary operators you'd like to add later (addition, subtraction, fuzzy string match, etc etc).
To convert from infix to postfix: http://scriptasylum.com/tutorials/infix_postfix/algorithms/infix-postfix/
To evaluate the postfix:
http://scriptasylum.com/tutorials/infix_postfix/algorithms/postfix-evaluation/
The easiest way to do this would be to parse the input text and build an array of boolean "true" values, so you end up with something like this:
//Dictionary<string,List<string>> members;
members["Car"].Contains("BMW") // evals to True;
Alternatively, if there's no functional difference between any of the input entries (i.e. the variable evaluates to true as long as the word shows up in the input text), you can probably just build a list of strings rather than having to worry about using their classification as the dictionary key.
Then, you parse the equation strings and see if the values are present in the boolean list, if they are, you replace them in the original equation string with a 1. If they are not present, you replace them with a 0.
You end up with something that looks like this:
string str0 = "Luke" // "1"
string str1 = "(Danny || Jennifer) && (BMW)" // "(1 || 0) && (1)"
string str2 = "(Mike && BMW) || Volvo" // "(1 && 1) || 0"
string str3 = "(Mike || David) && Ford" // "(1 || 1) && 0"
string str4 = "David && !BMW" // "1 && !0"
Now, it's just a simple iterative string replace. You loop on the string until the only thing remaining is a 1 or a 0.
while (str.Length > 1)
{
if (str.Contains("(1 || 1)"))
str.Replace("(1 || 1)", "1");
if (str.Contains("(1 || 0)"))
str.Replace("(1 || 0)", "1");
// and so on
}
Alternatively, if you can find a C# "eval" method, you can evaluate the expression directly (and you can also use True/False instead of 0/1).
Edit:
Found a simple tokenizer that will probably work for parsing the test equations:
using System;
using System.Text.RegularExpressions;
public static string[] Tokenize(string equation)
{
Regex RE = new Regex(#"([\(\)\! ])");
return (RE.Split(equation));
}
//from here: https://www.safaribooksonline.com/library/view/c-cookbook/0596003390/ch08s07.html
Edit 2:
Just wrote a sample project that does it.
//this parses out the string input, does not use the classifications
List<string> members = new List<string>();
string input = "Customers: David, Danny, Mike, Luke. Car: BMW";
string[] t1 = input.Split(new string[] {". "}, StringSplitOptions.RemoveEmptyEntries);
foreach (String t in t1)
{
string[] t2 = t.Split(new string[] { ": " }, StringSplitOptions.RemoveEmptyEntries);
string[] t3 = t2[1].Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
foreach (String s in t3)
{
members.Add(s.Trim());
}
}
This tokenizes the equation and replaces with 1 and 0.
string eq = "(Danny || Jennifer) && (!BMW)";
Regex RE = new Regex(#"([\(\)\! ])");
string[] tokens = RE.Split(eq);
string eqOutput = String.Empty;
string[] operators = new string[] { "&&", "||", "!", ")", "("};
foreach (string tok in tokens)
{
if (tok.Trim() == String.Empty)
continue;
if (operators.Contains(tok))
{
eqOutput += tok;
}
else if (members.Contains(tok))
{
eqOutput += "1";
}
else
{
eqOutput += "0";
}
}
At this point, the equation "(Danny || Jennifer) && (!BMW)" looks like "(1||0)&&(!1)".
Now reduce the equation to a 1 or 0.
while (eqOutput.Length > 1)
{
if (eqOutput.Contains("!1"))
eqOutput = eqOutput.Replace("!1", "0");
else if (eqOutput.Contains("!0"))
eqOutput = eqOutput.Replace("!0", "1");
else if (eqOutput.Contains("1&&1"))
eqOutput = eqOutput.Replace("1&&1", "1");
else if (eqOutput.Contains("1&&0"))
eqOutput = eqOutput.Replace("1&&0", "0");
else if (eqOutput.Contains("0&&1"))
eqOutput = eqOutput.Replace("0&&1", "0");
else if (eqOutput.Contains("0&&0"))
eqOutput = eqOutput.Replace("0&&0", "0");
else if (eqOutput.Contains("1||1"))
eqOutput = eqOutput.Replace("1||1", "1");
else if (eqOutput.Contains("1||0"))
eqOutput = eqOutput.Replace("1||0", "1");
else if (eqOutput.Contains("0||1"))
eqOutput = eqOutput.Replace("0||1", "1");
else if (eqOutput.Contains("0||0"))
eqOutput = eqOutput.Replace("0||0", "0");
else if (eqOutput.Contains("(1)"))
eqOutput = eqOutput.Replace("(1)", "1");
else if (eqOutput.Contains("(0)"))
eqOutput = eqOutput.Replace("(0)", "0");
}
Now you should have a string that contains only a 1 or a 0 indicating true or false, respectively.
With the help of DynamicExpresso you can easily do this in 10 lines. Let's say the text and the user input are like this:
var text = "Bob and Tom are in the same class.";
var input = "(Bob || Alice) && Tom";
You can consider "Bob" "Alice" "Tom" are variables whose type is bool in C#, the user input string becomes a valid C# expression, evaulate it using DynamicExpresso and get a bool result.
var variables = input.Split(new[] { "(", "||", "&&", ")", " " },
StringSplitOptions.RemoveEmptyEntries);
var interpreter = new Interpreter();
foreach (var variable in variables)
{
interpreter.SetVariable(variable, text.Contains(variable));
}
var result = (bool)interpreter.Parse(input).Invoke();
I need to extract the following data (in bold) from the text line below and put it into a data grid;
PERS tooldata t_rrt_ja03579:=[TRUE,[[-39.643,-0.001,1025.49],[0.382684,-0.000130001,-0.923889,0.000120001]],[200.9,[-88.1,-12.6,359.7],[1,0,0,0],29.347,50.927,18.261]];
This line is read from a file. I have managed to trim the line so it gets rid of the "PERS tooldata" and whitespaces and it leaves me with the tool name. I have it bound to data in a datagrid elsewhere in the code which is step 1 complete.
My question is how can I extract the values in bold individually and place them in to double data declarations? The first block of values (-39.643,-0.001,1025.49) is a X,Y,Z co-ordinate value and the second (0.382684,-0.000130001,-0.923889,0.000120001) are Q1,Q2,Q3,Q4.
Below is how i done the name
private void AutoFillToolData(object sender, RoutedEventArgs e)
{
// Gives user option to auto populate datagrid
var AutoFillToolResult = MessageBox.Show("Do you want to auto populate fields?", "Tool Data", MessageBoxButton.YesNo);
if (AutoFillToolResult == MessageBoxResult.Yes)
{
// User directs application to the specified file
System.Windows.Forms.FolderBrowserDialog folderBrowser = new System.Windows.Forms.FolderBrowserDialog();
if (folderBrowser.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
// Application looks for specific file and removes unwanted data
string robotBackupPath = folderBrowser.SelectedPath;
string allDataPath = robotBackupPath + #"\RAPID\TASK1\SYSMOD\ALL_DATA.sys";
string[] tLines = File.ReadAllLines(allDataPath);
List<string> toolDataLines = new List<string>();
foreach (string tLine in tLines)
{
if (tLine.Contains("PERS tooldata") && !tLine.StartsWith("!"))
{
if (tLine.Contains("tToolChanger")) continue;
if (tLine.Contains("tPointer")) continue;
if (tLine.Contains("tHome")) continue;
toolDataLines.Add(tLine);
}
}
foreach (string line in toolDataLines)
{
// Gets the name of the tool
ToolData toolData = GetToolNameFromLine(line);
// Puts the tool name in the DataGrid
TCPData.Add(toolData);
}
}
}
}
private ToolData GetToolNameFromLine(string line)
{
// Removes white space at the beggining of line in txt file
ToolData tooldata = new ToolData();
string[] spaceSplit = line.Trim().Split(' ');
string values = spaceSplit[2];
// Gets Tool Name
int colonLocation = values.IndexOf(":");
tooldata.ToolName = values.Substring(0, colonLocation);
return tooldata;
}
If all the samples you'll have follow the same pattern, extracting those values does not seem difficult:
//First we get all the string after the :=
string tooldata = line.Substring(data.IndexOf(":=") + 2) ;
//Split the string by [
string[] tooldataArray = tooldata.Split(new char[] { '[' }, StringSplitOptions.RemoveEmptyEntries);
//the second and the third strings are what we are interested in
string xyzValue = tooldataArray[1].Replace(']' ,' ');
string Q1234value = tooldataArray[2].Replace(']', ' ');
If after this you want to get the individual parameters, just splitting by , would do.
Edit
This would extract all the values you want to arrays of double:
string tooldata = data.Substring(data.IndexOf(":=") + 2) ;
string[] tooldataArray = tooldata.Split(new char[] { '[' }, StringSplitOptions.RemoveEmptyEntries);
double[] xyzValue = tooldataArray[1].Replace(']' ,' ')
.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(s => double.Parse(s, CultureInfo.InvariantCulture))
.ToArray();
double[] Q1234value = tooldataArray[2].Replace(']', ' ')
.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(s => double.Parse(s, CultureInfo.InvariantCulture))
.ToArray();
i got error as: An unhandled exception of type 'System.IndexOutOfRangeException' occurred in app.exe
Additional information: Index was outside the bounds of the array.
by using code below, i appreciate your help in-advance all.
public string getMissingFields(WebBrowser wb, DataRow dr)
{
string Available2 = "";
Available2 = wb.Document.GetElementById("ContentPlaceHolder1_reqTxt")
.Style.Split(';')
.Where(x => x.Contains("display"))
.ToArray()[0].Split(':')[1];
string FieldsMissing="";
if( Available2 .Contains( "inline" )) {
FieldsMissing = FieldsMissing + "First name missing!" + ", ";
}
return FieldsMissing;
}
You're assumiing that the style will always contain "display", which apparently it does not. Replace your indexer call to offset 0 with a call to FirstOrDefault(), then test for null:
Available2 = wb.Document.GetElementById("ContentPlaceHolder1_reqTxt").Style.Split(';').Where(x => x.Contains("display")).ToArray().FirstOrDefault();
if( null != Available2 )
{
// continue
}
Available2 = wb.Document.GetElementById("ContentPlaceHolder1_reqTxt")
.Style.Split(';')
.Where(x => x.Contains("display"))
.ToArray()[0].Split(':')[1];
Two possible problems:
Either ToArray() does return an empty array, at with point accessing element 0 causes this error. Or it is at the point where you are accessing the element at index 1 - maybe there is no such element, because in the string you're trying to split there is no :? Debug your code or make sure that there is at least one element returned by ToArray() and two elements returned by Split.
You could try this now. This splits your code so that you can easily debug:
var items = wb.Document.GetElementById("ContentPlaceHolder1_reqTxt")
.Style.Split(';')
.Where(x => x.Contains("display"))
.ToArray();
if (items.Count > 0)
{
string[] split = items[0].Split(':');
if (split.Length > 1)
Available2 = split[1];
}
Two possibilities:
ToArray() returning empty array.You are trying to an element which is not exist.
Split(':') returning zero or one element.
Debug your code and find which one is true.
It seems you don't need ToArray.Just use FirstOrDefault, and check returning result whether null or not.If it isn't null call Split and check again to prevent exception.
Available2 = wb.Document.GetElementById("ContentPlaceHolder1_reqTxt")
.Style.Split(';')
.Where(x => x.Contains("display"))
.FirstOrDefault();
if(Available2 != null)
{
var text = Available2.Split(':');
if(text.Length > 1)
{
var result = text[1];
}
}
First, consider that there's no control with id=ContentPlaceHolder1_reqTxt:
var reqTxt = wb.Document.GetElementById("ContentPlaceHolder1_reqTxt");
You have to handle the case that it's null:
if(reqTxt != null)
{
}
Now consider that there's is no style display, then ToArray returns an empty array. You can use FirstOrDefault and check for null gain:
string Available2 = null;
if(reqTxt != null)
{
var firstDisplayStyle = reqTxt.Split(';')
.FirstOrDefault(s => s.Contains("display"));
if(firstDisplayStyle != null)
{
string[] displaySplit = firstDisplayStyle.Split(':');
// now handle the case that there is no colon:
if(displaySplit.Length > 1)
Available2 = displaySplit[1];
}
}
Available2=wb.Document.GetElementById("ContentPlaceHolder1_reqTxt").Style.Split(';').Where(x => x.Contains("display")).ToArray()[0].Split(':')[1];
To find problem, decomposite to:
if (wb == null || wb.Document == null )
return;
var element = wb.Document.GetElementById("ContentPlaceHolder1_reqTxt");
if (element == null || element.Style == null)
return;
var displayItems = element.style.Split(';').Where(x=> x.Contains("display")).FirstOrDefault();
if ( displayItems == null)
return;
var colonItems = displayItems.Split(':');
if ( colonItems.Count() < 2 )
return;
var Available2 = colonItems.Skip(1).First();