How to get string after specific string? - c#

How to get string after text "playlist:" ?
var YT= "tag:youtube.com,2008:user:hollywoodlife09:playlist:PLDovhwKa3P88MwGzYxMDMfiAiiEWxAJYj" ;
What I did :
string[] s = YT.Split(':');
But it will give me array i.e s[0],s[1] ... and I am searching for something which can give result after specific text.
I want string after "playlist:", I know it may be easy with Regex,but currently I don't have any idea for Regex..

You can use Substring method
var output = inputString.SubString(inputString.LastIndexOf("playlist") + 8);
Or in this case it can be done using Last method via Split:
string output = YT.Split(':').Last();

Using regex replace, remove everything before the :playlist: with empty string.
string playlist = Regex.Replace(YT, ".*:playlist:", "");

more reusably,
static IEnumerable<KeyValuePair<string, string>> SplitPairs(
this string source,
params char[] seperators)
{
var values = source.Split(seperators);
for(var i = 0; i < values.Length; i += 2)
{
yield return new KeyValuePair<string, string>(
values[i],
values[i + 1]);
}
}
so you could do,
var yTlookup = YT.SplitPairs(':').ToDictionary(p => p.Key, p => p.Value);
var playList = yTLookup["playlist"];
or if you don't want an extension,
var segments = YS.Split(new[] { ':' });
var ySlookup = Enumerable.Range(0, segemnts.Length / 2)
.ToDictionary(i => segments[i * 2], i => segments[(i * 2) + 1]);
so you can do,
var playlist = ysLookup["playlist"];
either approach pays off as soon as you want another value from the sequence.

The regex is .+playlist:([^:])

Related

Get count of unique characters between first and last letter

I'm trying to get the unique characters count that are between the first and last letter of a word. For example: if I type Yellow the expected output is Y3w, if I type People the output should be P4e and if I type Money the output should be M3y. This is what I tried:
//var strArr = wordToConvert.Split(' ');
string[] strArr = new[] { "Money","Yellow", "People" };
List<string> newsentence = new List<string>();
foreach (string word in strArr)
{
if (word.Length > 2)
{
//ignore 2-letter words
string newword = null;
int distinctCount = 0;
int k = word.Length;
int samecharcount = 0;
int count = 0;
for (int i = 1; i < k - 2; i++)
{
if (word.ElementAt(i) != word.ElementAt(i + 1))
{
count++;
}
else
{
samecharcount++;
}
}
distinctCount = count + samecharcount;
char frst = word[0];
char last = word[word.Length - 1];
newword = String.Concat(frst, distinctCount.ToString(), last);
newsentence.Add(newword);
}
else
{
newsentence.Add(word);
}
}
var result = String.Join(" ", newsentence.ToArray());
Console.WriteLine("Output: " + result);
Console.WriteLine("----------------------------------------------------");
With this code I'm getting the expect output for Yellow, but seems that is not working with People and Money. What can I do to fix this issue or also I'm wondering is maybe there is a better way to do this for example using LINQ/Regex.
Here's an implementation that uses Linq:
string[] strArr = new[]{"Money", "Yellow", "People"};
List<string> newsentence = new List<string>();
foreach (string word in strArr)
{
if (word.Length > 2)
{
// we want the first letter, the last letter, and the distinct count of everything in between
var first = word.First();
var last = word.Last();
var others = word.Skip(1).Take(word.Length - 2);
// Case sensitive
var distinct = others.Distinct();
// Case insensitive
// var distinct = others.Select(c => char.ToLowerInvariant(c)).Distinct();
string newword = first + distinct.Count().ToString() + last;
newsentence.Add(newword);
}
else
{
newsentence.Add(word);
}
}
var result = String.Join(" ", newsentence.ToArray());
Console.WriteLine(result);
Output:
M3y Y3w P4e
Note that this doesn't take account of case, so the output for FiIsSh is 4.
Maybe not the most performant, but here is another example using linq:
var words = new[] { "Money","Yellow", "People" };
var transformedWords = words.Select(Transform);
var sentence = String.Join(' ', transformedWords);
public string Transform(string input)
{
if (input.Length < 3)
{
return input;
}
var count = input.Skip(1).SkipLast(1).Distinct().Count();
return $"{input[0]}{count}{input[^1]}";
}
You can implement it with the help of Linq. e.g. (C# 8+)
private static string EncodeWord(string value) => value.Length <= 2
? value
: $"{value[0]}{value.Substring(1, value.Length - 2).Distinct().Count()}{value[^1]}";
Demo:
string[] tests = new string[] {
"Money","Yellow", "People"
};
var report = string.Join(Environment.NewLine, tests
.Select(test => $"{test} :: {EncodeWord(test)}"));
Console.Write(report);
Outcome:
Money :: M3y
Yellow :: Y3w
People :: P4e
A lot of people have put up some good solutions. I have two solutions for you: one uses LINQ and the other does not.
LINQ, Probably not much different from others
if (str.Length < 3) return str;
var midStr = str.Substring(1, str.Length - 2);
var midCount = midStr.Distinct().Count();
return string.Concat(str[0], midCount, str[str.Length - 1]);
Non-LINQ
if (str.Length < 3) return str;
var uniqueLetters = new Dictionary<char, int>();
var midStr = str.Substring(1, str.Length - 2);
foreach (var c in midStr)
{
if (!uniqueLetters.ContainsKey(c))
{
uniqueLetters.Add(c, 0);
}
}
var midCount = uniqueLetters.Keys.Count();
return string.Concat(str[0], midCount, str[str.Length - 1]);
I tested this with the following 6 strings:
Yellow
Money
Purple
Me
You
Hiiiiiiiii
Output:
LINQ: Y3w, Non-LINQ: Y3w
LINQ: M3y, Non-LINQ: M3y
LINQ: P4e, Non-LINQ: P4e
LINQ: Me, Non-LINQ: Me
LINQ: Y1u, Non-LINQ: Y1u
LINQ: H1i, Non-LINQ: H1i
Fiddle
Performance-wise I'd guess they're pretty much the same, if not identical, but I haven't run any real perf test on the two approaches. I can't imagine they'd be much different, if at all. The only real difference is that the second route expands Distinct() into what it probably does under the covers anyway (I haven't looked at the source to see if that's true, but that's a pretty common way to get a count of . And the first route is certainly less code.
I Would use Linq for that purpose:
string[] words = new string[] { "Yellow" , "People", "Money", "Sh" }; // Sh for 2 letter words (or u can insert 0 and then remove the trinary operator)
foreach (string word in words)
{
int uniqeCharsInBetween = word.Substring(1, word.Length - 2).ToCharArray().Distinct().Count();
string result = word[0] + (uniqeCharsInBetween == 0 ? string.Empty : uniqeCharsInBetween.ToString()) + word[word.Length - 1];
Console.WriteLine(result);
}

Split and then Joining the String step by step - C# Linq

Here is my string:
www.stackoverflow.com/questions/ask/user/end
I split it with / into a list of separated words:myString.Split('/').ToList()
Output:
www.stackoverflow.com
questions
ask
user
end
and I need to rejoin the string to get a list like this:
www.stackoverflow.com
www.stackoverflow.com/questions
www.stackoverflow.com/questions/ask
www.stackoverflow.com/questions/ask/user
www.stackoverflow.com/questions/ask/user/end
I think about linq aggregate but it seems it is not suitable here. I want to do this all through linq
You can try iterating over it with foreach
var splitted = "www.stackoverflow.com/questions/ask/user/end".Split('/').ToList();
string full = "";
foreach (var part in splitted)
{
full=$"{full}/{part}"
Console.Write(full);
}
Or use linq:
var splitted = "www.stackoverflow.com/questions/ask/user/end".Split('/').ToList();
var list = splitted.Select((x, i) => string.Join("/", a.Take(i + 1)));
Linq with side effect:
string prior = null;
var result = "www.stackoverflow.com/questions/ask/user/end"
.Split('/')
.Select(item => prior == null
? prior = item
: prior += "/" + item)
.ToList();
Let's print it out
Console.WriteLine(string.Join(Environment.NewLine, result));
Outcome:
www.stackoverflow.com
www.stackoverflow.com/questions
www.stackoverflow.com/questions/ask
www.stackoverflow.com/questions/ask/user
www.stackoverflow.com/questions/ask/user/end
Linq without side effects ;)
Enumerable.Aggregate can be used here if we use List<T> as a result.
var raw = "www.stackoverflow.com/questions/ask/user/end";
var actual =
raw.Split('/')
.Aggregate(new List<string>(),
(list, word) =>
{
var combined = list.Any() ? $"{list.Last()}/{word}" : word;
list.Add(combined);
return list;
});
without Linq write below code,
var str = "www.stackoverflow.com/questions/ask/user/end";
string[] full = str.Split('/');
string Result = string.Empty;
for (int i = 0; i < full.Length; i++)
{
Console.WriteLine(full[i]);
}
for (int i = 0; i < full.Length; i++)
{
if (i == 0)
{
Result = full[i];
}
else
{
Result += "/" + full[i];
}
Console.WriteLine(Result);
}

I want substring from set of string after a pattern exist in c#

I have 3 string ---
m60_CLDdet2_LOSS2CLF_060520469434_R0RKE_52_GU
m60_CLDdet2_LOSS2CLF_060520469434_R10KE_52_TCRER
m60_CLDdet2_LOSS2CLF_060520469434_R0HKE_52_NT
and I want R0RKE_52_GU, R10KE_52_TCRER,R0HKE_52_NT.
Note: m60_CLDdet2_LOSS2CLF_060520469434 is varying so I want to find substring if R0RKE or R10KE or R0HKE exists
I would suggest using a Regular expression for this, it is much more versatile for pattern matching.
var matches = System.Text.RegularExpressions.Regex.Matches(text, #"(R0RKE|R10KE|R0HKE).*");
I want to find substring if R0RKE or R10KE or R0HKE exists
This LINQ query returns the desired result:
var strings=new[]{"m60_CLDdet2_LOSS2CLF_060520469434_R0RKE_52_GU","m60_CLDdet2_LOSS2CLF_060520469434_R10KE_52_TCRER","m60_CLDdet2_LOSS2CLF_060520469434_R0HKE_52_NT"};
string[] starts = { "R0RKE", "R10KE", "R0HKE" };
var result = strings
.Select(str => new { str, match = starts.FirstOrDefault(s => str.IndexOf("_" + s) >= 0)})
.Where(x => x.match != null)
.Select(x => x.str.Substring(x.str.IndexOf(x.match)));
Console.Write(String.Join(",", result)); // R0RKE_52_GU,R10KE_52_TCRER,R0HKE_52_NT
I write it into static method:
private static string TakeIt(string inputString)
{
if (!Regex.IsMatch(inputString, "(R0RKE|R10KE|R0HKE)"))
{
return string.Empty;
}
var regex = new Regex(#"_");
var occurances = regex.Matches(inputString);
var index = occurances[3].Index + 1;
return inputString.Substring(index, inputString.Length - index);
}
void Main()
{
var string1 = "m60_CLDdet2_LOSS2CLF_060520469434_R0RKE_52_GU";
var string2 = "m60_CLDdet2_LOSS2CLF_060520469434_R10KE_52_TCRER";
var string3 = "m60_CLDdet2_LOSS2CLF_060520469434_R0HKE_52_NT";
var string4 = "m60_CLDdet2_LOSS2CLF_060520469434_hhhhh";
Console.WriteLine(TakeIt(string1));
Console.WriteLine(TakeIt(string2));
Console.WriteLine(TakeIt(string3));
Console.WriteLine(TakeIt(string4));
}
Hope this help.
Update: added .Any - it simplifies the code and it's just as same efficient.
If you just need to check for three strings inside string array you can do :
static string[] GetStrings(string[] dirty, string[] lookUpValues)
{
List<string> result = new List<string>();
for (int i = 0; i < dirty.Length; i++) if (lookUpValues.Any(dirty[i].Contains)) result.Add(dirty[i]);
return result.ToArray();
}
Usage: string[] result = GetStrings(dirty, new[] {"R0RKE", "R10KE", "R0HKE"});
Also you can use LINQ query and Regex.Matches as others advised.

Linq lambda foreach

Trying for wrap each string in array but it doesn't works, means foreach loop, please explain why
string s = "keepsakes,table runners,outdoor accessories";
List<string> keys = s.Split(',').ToList();
keys.ForEach(x => x = String.Concat("%", x, "%"));
s = String.Join(",", keys);
Console.WriteLine(s);
need to get "%keepsakes%,%table runners%,%outdoor accessories%"
UPD:
Thanks a lot for suggestions(it's a same way)
but some one can answer why this is works and not works under:
object
public class MyItems
{
public string Item { get; set; }
}
and func
string s = "keepsakes,table runners,outdoor accessories";
List<MyItems> keys = s.Split(',').ToList().Select(x => new MyItems(){ Item = x }).ToList();
keys.ForEach(x => x.Item = String.Concat("%", x.Item, "%"));
s = String.Join(",", keys.Select(x => x.Item).ToList());
Console.WriteLine(s);
You are not modifying the list within the ForEach, you are just creating strings that are assigned to the local variable x but then thrown away. You could use a for-loop:
for(int i = 0; i < keys.Count; i++)
{
keys[i] = String.Concat("%", keys[i], "%");
}
For what it's worth, here the shorter LINQ version which also circumvents the core issue:
s = string.Join(",", s.Split(',').Select(str => "%" + str + "%"));
You can use Join and Select and Format
string s = "keepsakes,table runners,outdoor accessories";
var output = string.Join(",", s.Split(',').Select(x => string.Format("%{0}%", x)));
you can do easier: replace each comma with %,%
string s = "keepsakes,table runners,outdoor accessories";
string s2 = "%" + s.Replace("," , "%,%") + "%";
Another approach could be using Regex instead of LINQ:
string s = "keepsakes,table runners,outdoor accessories";
string pattern = "\\,+";
string replacement = "%,";
Regex rgx = new Regex(pattern);
string result = string.Format("%{0}%", rgx.Replace(s, replacement));
Edit:
The reason why it works using a class to assign the string it is because when you use the foreach in your first instance:
keys.ForEach(x => x = String.Concat("%", x, "%"));
x, elements of keys, which is a string, is a reference passed by value to the function ForEach. Take this as an example:
var myString = "I'm a string";
Console.WriteLine(myString);
ChangeValue(myString);
Console.WriteLine(myString);
void ChangeValue(string s)
{
s = "something else";
}
If you run that snippet you'll see that myString won't be changed inside the method ChangeValue because we are trying to replace the reference. The same thing happens for the method ForEach, this is the main reason you cannot change the value of your list within the ForEach.
Instead if you do:
class MyClass{
public string aString;
}
void ChangeValue(MyClass s)
{
s.aString = "something else";
}
var myClass = new MyClass();
myClass.aString = "I'm a string";
Console.WriteLine(myClass.aString);
ChangeValue(myClass);
Console.WriteLine(myClass.aString);
You acknowledge that in the second Console.WriteLine the value of the field aString will be changed to "something else". Here is a good explanation of how reference types are passed by value
Just another approach (without lambdas):
string result = string.Concat("%", s, "%").Replace(",", "%,%");
List<>.ForEach cannot be used to change the contents of the list. You can either create a new list or use a for loop.
keys = keys.Select(x => "%" + x + "%").ToList();
or
for(int i = 0; i < keys.Count; i++)
{
keys[i] = "%" + keys[i] + "%";
}
As others have noted, the lambda passed to List.ForEach does not return a value.
LINQ is lazy, but String.Join will force enumeration:
var res = String.Join(",", input.Split(',').Select(s => "%" + s + "%"));
The ForEach doesn't change your list of string, it will only perform an action using each string. Instead you can do it this way :
string s = "keepsakes,table runners,outdoor accessories";
List<string> keys = s.Split(',').Select(x => String.Concat("%", x, "%")).ToList();
s = String.Join(",", keys);
Console.WriteLine(s);

C# Reading particular values in a string

I have the following line from a string:
colors numResults="100" totalResults="6806926"
I want to extract the value 6806926 from the above string
How is it possible?
So far, I have used StringReader to read the entire string line by line.
Then what should I do?
I'm sure there's also a regex, but this string approach should work also:
string xmlLine = "[<colors numResults=\"100\" totalResults=\"6806926\">]";
string pattern = "totalResults=\"";
int startIndex = xmlLine.IndexOf(pattern);
if(startIndex >= 0)
{
startIndex += pattern.Length;
int endIndex = xmlLine.IndexOf("\"", startIndex);
if(endIndex >= 0)
{
string token = xmlLine.Substring(startIndex,endIndex - startIndex);
// if you want to calculate with it
int totalResults = int.Parse( token );
}
}
Demo
Consider the this is in Mytext of string type variable
now
Mytext.Substring(Mytext.indexof("totalResults="),7);
//the function indexof will return the point wheres the value start,
//and 7 is a length of charactors that you want to extract
I am using similar of this ........
You can read with Linq2Xml, numResults and totalResults are Attributes, and <colors numResults="100" totalResults="6806926"> is Element, so you can simply get it by nmyXmlElement.Attributes("totalResults").
This function will split the string into a list of key value pairs which you can then pull out whatever you require
static List<KeyValuePair<string, string>> getItems(string s)
{
var retVal = new List<KeyValuePair<String, string>>();
var items = s.Split(' ');
foreach (var item in items.Where(x => x.Contains("=")))
{
retVal.Add(new KeyValuePair<string, string>( item.Split('=')[0], item.Split('=')[1].Replace("\"", "") ));
}
return retVal;
}
You can use regular expressions:
string input = "colors numResults=\"100\" totalResults=\"6806926\"";
string pattern = "totalResults=\"(?<results>\\d+?)\"";
Match result = new Regex(pattern).Match(input);
Console.WriteLine(result.Groups["results"]);
Be sure to have this included:
using System.Text.RegularExpressions;

Categories