I have a string
(ProductAttributes,MapType(StringType,StructType(
List( (CurrentValue,StringType,true), (OldValue,StringType,true),
(LastValue,StringType,true))),true),true)
I need to extract StructType(List( (CurrentValue,StringType,true), (OldValue,StringType,true), (LastValue,Stringy )
I've used string.split using separator as "," but I'm not getting the entire struct string.The string I got while using ","
(ProductAttributes
MapType(StringType
StructType(List( (CurrentValue
StringType
true)
(OldValue
StringType
true)
(LastValue
StringType
true)))
true)
true)
I can give the count parameter as '3' but my string might change.I tried giving separator as '()' the got the full string .
The expected result is something like this.I can build this string using an object but extracting the values from the string is a blocker for me now
{"FieldId":"401","Name":"CurrentValue","Type":"string","ParentName":"ProductAttributes>CurrentValue","ParentId":"4"}
Another string example would be:
(BusinessRules,ArrayType(StructType(List( (Id,IntegerType,true), (ErrorCode,IntegerType,true), (Overrides,ArrayType(StructType(List( (OverrideSource,IntegerType,true), (IsOverridden,BooleanType,true), (ReasonId,IntegerType,true), (OverriddenBy,StringType,true), (OverrideDate,LongType,true), (DependencyProductAttributeIds,ArrayType(IntegerType,true),true))),true),true))),true),true)
As stated in the comments it is hard to know how your string might change in the future, but this answer could be used as a starting point (as it will work with the string you have already provided)
You can find the first instance of StructType and then count the number of ( between the start of the string and the found instance. Then count the same number of ) from the end of the string to get your substring.
var stringToParse = #" (ProductAttributes,MapType(StringType,StructType(
List( (CurrentValue,StringType,true), (OldValue,StringType,true),
(LastValue,StringType,true))),true),true)";
var start = stringToParse.IndexOf("StructType(");
var count = stringToParse.Substring(0, start).Count(c => c == '(');
var end = stringToParse.Length;
for(int i = 0; i < count + 1; i++)
{
end = stringToParse.LastIndexOf(')', end - 1);
}
var result = stringToParse.Substring(start, end - start);
Console.WriteLine(result);
Note: We add 1 to the ( count in the for loop to ensure we count back to the matching ) for our initial search string StructType(
Related
How can i find an operator in the string? After that, I'd like to create get the left and the right variable.
If the string was:
DisengagementPoint=TravelForce
or
DisengagementPoint=100
but some time string be longer like:
DisengagementPoint=100 (VehicleSpeed>2) || (EngineRpm== 0)
And I want to create a string with whatever is on the left side of "=" and one string with right side, how could I do that?
Output that I expected:
var1 = DisengagementPoint
var2 = 100 or TravelForce
var3 = (VehicleSpeed>2) || (EngineRpm== 0)
Sorry this is pretty pseudo, but hopefully it makes sense.
I would like add two things to other excelent answers:
A) The string.Split splits the string by all equals thus DisengagementPoint=100 would go out just fine but line = "DisengagementPoint=100 (VehicleSpeed>2) || (EngineRpm== 0)" would get quite messy since just splitting with string string[] split = line.Split('=') would yield array:
split[0] = "DisengagementPoint"
split[1] = "100 (VehicleSpeed>2) || (EngineRpm"
split[2] = ""
split[3] = " 0)"
This can be eliminated by restricting maximal number of splits with line.Split('=', 2) returns maximally two sub-strings. And also line.Split('=', StringSplitOptions.RemoveEmptyEntries) could help to get rid if empty parts, but this would not be an issue in this case.
B) What with problem of comparison operator ==? Perheaps check if there are only a single equals or more of them and if more, if there are at least two of them right behind themselves.
As mentioned in comment to #Dmitry Bychenko´s post by #AustinWBryan this starts to look parser problem, which is a bit different question in my opinion.
Just find = position and take substrings:
String source = "DisengagementPoint=100";
int index = source.IndexOf('=');
// you may want to test if there's '=' in the string
// if (index >= 0) ...
String left = source.Substring(0, index);
String right = source.Substring(index + 1);
var word = "DisengagementPoint=TravelForce";
var index = word.IndexOf("=");
if(index > 1)
{
var left = word.Substring(0, index);
var right = word.Substring(index + 1,word.Length - index - 1);
}
As DmitryBychenko mentioned
var right = word.Substring(index + 1,word.Length - index - 1);
can be replaced with
var right = word.Substring(index + 1);
I have a list of string where one item is like, textItem1 = "Brown, Adam. (user)(admin)(Sales)" where I would always have to extract the text from the last pair of parentheses, which in this case will be Sales.
I tried the following:
string name = DDlistName.SelectedItem.ToString();
int start = name.IndexOf("(");
int end = name.IndexOf("(");
string result = name.Substring(start + 1, end - start - 1);
_UILabelPrintName.Text = result;
Problem: This always picks the text from first pair of parentheses, which in this case user.
Reading lots of similar question's answer I realised Regex might not be recommended in this case (not particularly succeeded either trying other codes). However any help with any short routine which can do the task will be really appreciated.
You need to use LastIndexOf instead of IndexOf, and check for a close parenthesis at the end.
string name = "Brown, Adam. (user)(admin)(Sales)";
int start = name.LastIndexOf("(");
int end = name.LastIndexOf(")");
string result = name.Substring(start + 1, end - start - 1);
Really you'd want to validate start and end to be sure that both parenthesis were found. LastIndexOf returns -1 if the character is not found.
And in order to handle nesting we need to search forward for the closing parenthesis after the location of the opening parenthesis.
string name = "Brown, Adam. (user)(admin)((Sales))";
int start = name.LastIndexOf('(');
int end = (start >= 0) ? name.IndexOf(')', start) : -1;
string result = (end >= 0) ? name.Substring(start + 1, end - start - 1) : "";
You can use the split function, breaking the string at the opening parenthesis. The last array element is the desired output with a tailing ")", which will then be removed.
var input = "Brown, Adam. (user)(admin)(Sales)";
// var input = DDlistName.SelectedItem.ToString();
var lastPick = input.Split(new[] { "(" }, StringSplitOptions.RemoveEmptyEntries).Last();
var output = lastPick.Substring(0, lastPick.Length - 1);
_UILabelPrintName.Text = output;
Another approach is to use a while loop with IndexOf. It cuts the input string as long as another "(" is found. If not more "(" are found, it takes the contents of the remaining string until the closing parenthesis ")":
int current = -1;
while(name.IndexOf("(") > 0)
{
name = name.Substring(name.IndexOf("(") + 1);
}
var end = name.IndexOf(")");
var output = name.Substring(0, end);
_UILabelPrintName.Text = output;
Or use LastIndexOf....
I have the following main string which contains link Name and link URL. The name and url is combined with #;. I want to get the string of each link (name and url i.e. My web#?http://www.google.com), see example below
string teststring = "My web#;http://www.google.com My Web2#;http://www.bing.se Handbooks#;http://www.books.se/";
and I want to get three different strings using any string function:
My web#?http://www.google.com
My Web2#?http://www.bing.se
Handbooks#?http://www.books.de
So this looks like you want to split on the space after a #;, instead of splitting at #; itself. C# provides arbitrary length lookbehinds, which makes that quite easy. In fact, you should probably do the replacement of #; with #? first:
string teststring = "My web#;http://www.google.com My Web2#;http://www.bing.se Handbooks#;http://www.books.se/";
teststring = Regex.Replace(teststring, #"#;", "#?");
string[] substrings = Regex.Split(teststring, #"(?<=#\?\S*)\s+");
That's it:
foreach(var s in substrings)
Console.WriteLine(s);
Output:
My web#?http://www.google.com
My Web2#?http://www.bing.se
Handbooks#?http://www.books.se/
If you are worried that your input might already contain other #? that you don't want to split on, you can of course do the splitting first (using #; in the pattern) and then loop over substrings and do the replacement call inside the loop.
If these are constant strings, you can just use String.Substring. This will require you to count letters, which is a nuisance, in order to provide the right parameters, but it will work.
string string1 = teststring.Substring(0, 26).Replace(";","?");
If they aren't, things get complicated. You could almost do a split with " " as the delimiter, except that your site name has a space. Do any of the substrings in your data have constant features, such as domain endings (i.e. first .com, then .de, etc.) or something like that?
If you have any control on the input format, you may want to change it to be easy to parse, for example by using another separator between items, other than space.
If this format can't be changed, why not just implement the split in code? It's not as short as using a RegEx, but it might be actually easier for a reader to understand since the logic is straight forward.
This will almost definitely will be faster and cheaper in terms of memory usage.
An example for code that solves this would be:
static void Main(string[] args)
{
var testString = "My web#;http://www.google.com My Web2#;http://www.bing.se Handbooks#;http://www.books.se/";
foreach(var x in SplitAndFormatUrls(testString))
{
Console.WriteLine(x);
}
}
private static IEnumerable<string> SplitAndFormatUrls(string input)
{
var length = input.Length;
var last = 0;
var seenSeparator = false;
var previousChar = ' ';
for (var index = 0; index < length; index++)
{
var currentChar = input[index];
if ((currentChar == ' ' || index == length - 1) && seenSeparator)
{
var currentUrl = input.Substring(last, index - last);
yield return currentUrl.Replace("#;", "#?");
last = index + 1;
seenSeparator = false;
previousChar = ' ';
continue;
}
if (currentChar == ';' && previousChar == '#')
{
seenSeparator = true;
}
previousChar = currentChar;
}
}
The title explains it all. It seems simple enough, so I must be overlooking something stupid. Here's what I've got.
private string getBetween(string strSource, string strStart, string strEnd)
{
int start, end;
if (strSource.Contains(strStart) && strSource.Contains(strEnd))
{
start = strSource.IndexOf(strStart, 0) + strStart.Length;
end = strSource.IndexOf(strEnd, start);
return strSource.Substring(start, end - start);
}
else
{
return "";
}
}
Thanks, guys.
Your code doesn't make sure that start and end are in order.
static string SubString(string source, string prefix, string suffix)
{
int start = source.IndexOf(prefix); // get position of prefix
if (start == -1)
return String.Empty;
int subStart = start + prefix.Length; // get position of substring
int end = source.IndexOf(suffix, subStart); // make sure suffix also exists
if (end == -1)
return String.Empty;
int subLength = end - subStart; // calculate length of substring
if (subLength == 0)
return String.Empty;
return source.Substring(subStart, subLength); // return substring
}
As couple of peoples said the problem that you code is working on very specific input, it's all because of this start and end IndexOf magic =) But when you try to update you code to work correct on more inputs you will get into problem that your code become very long with many indexes, comparsions, substrings, conditions and so on. To avoid this i like to recommend you use regular expressions with theirs help you can express what you need on special language.
Here is the sample which solves your problem with regular expressions:
public static string getBetween(string source, string before, string after)
{
var regExp = new Regex(string.Format("{0}(?<needle>[^{0}{1}]+){1}",before,after));
var matches = regExp.Matches(source).Cast<Match>(). //here we use LINQ to
OrderBy(m => m.Groups["needle"].Value.Length). //find shortest string
Select(m => m.Groups["needle"].Value); //you can use foreach loop instead
return matches.FirstOrDefault();
}
All tricky part is {0}(?<needle>[^{0}{1}]+){1} where 0 - before string and 1 - after string. This expression means that we nned to find string that lies beetween 0 and 1, and also don't contains 0 and 1.
Hope this helps.
I get the correct answer if I try any of these:
var a = getBetween("ABC", "A", "C");
var b = getBetween("TACOBBURRITO", "TACO", "BURRITO");
var c = getBetween("TACOBACONBURRITO", "TACO", "BURRITO");
The problem is likely with your input argument validation, as this fails:
var a = getBetween("ABC", "C", "A");
var a = getBetween("ABC", "C", "C");
You can improve your validation of the issue by writing some test cases like these as a separate fixture (xUnit, or main loop in throw away app).
Suppose I have a string "011100011".
Now I need to find another string by adding the adjacent digits of this string, like the output string should be "123210122".
How do I split each characters in the string and manipulate them?
The method that I thought was to convert the string to integer using Parsing and splitting each character using modulus or something and performing operations on them.
But can you suggest some simpler methods?
Here's a solution which uses some LINQ plus dahlbyk's idea:
string input = "011100011";
// add a 0 at the start and end to make the loop simpler
input = "0" + input + "0";
var integers = (from c in input.ToCharArray() select (int)(c-'0'));
string output = "";
for (int i = 0; i < input.Length-2; i++)
{
output += integers.Skip(i).Take(3).Sum();
}
// output is now "123210122"
Please note:
the code is not optimized. E.g. you might want to use a StringBuilder in the for loop.
What should happen if you have a '9' in the input string -> this might result in two digits in the output string.
Try converting the string to a character array and then subtract '0' from the char values to retrieve an integer value.
string input = "011100011";
int current;
for (int i = 0; i < input.Length; i ++)
{
current = int.Parse(input[i]);
// do something with current...
}