I have a string that looks like this:
var expression = #"Args("token1") + Args("token2")";
I want to retrieve a collection of strings that are enclosed in Args("") in the expression.
How would I do this in C# or VB.NET?
Regex:
string expression = "Args(\"token1\") + Args(\"token2\")";
Regex r = new Regex("Args\\(\"([^\"]+)\"\\)");
List<string> tokens = new List<string>();
foreach (var match in r.Matches(expression)) {
string s = match.ToString();
int start = s.IndexOf('\"');
int end = s.LastIndexOf('\"');
tokens.add(s.Substring(start + 1, end - start - 1));
}
Non-regex (this assumes that the string in the correct format!):
string expression = "Args(\"token1\") + Args(\"token2\")";
List<string> tokens = new List<string>();
int index;
while (!String.IsNullOrEmpty(expression) && (index = expression.IndexOf("Args(\"")) >= 0) {
int start = expression.IndexOf('\"', index);
string s = expression.Substring(start + 1);
int end = s.IndexOf("\")");
tokens.Add(s.Substring(0, end));
expression = s.Substring(end + 2);
}
There is another regular expression method for accomplishing this, using lookahead and lookbehind assertions:
Regex regex = new Regex("(?<=Args\\(\").*?(?=\"\\))");
string input = "Args(\"token1\") + Args(\"token2\")";
MatchCollection matches = regex.Matches(input);
foreach (var match in matches)
{
Console.WriteLine(match.ToString());
}
This strips away the Args sections of the string, giving just the tokens.
If you want token1 and token2, you can use following regex
input=#"Args(""token1"") + Args(""token2"")"
MatchCollection matches = Regex.Matches(input,#"Args\(""([^""]+)""\)");
Sorry, If this is not what you are looking for.
if your collection looks like this:
IList<String> expression = new List<String> { "token1", "token2" };
var collection = expression.Select(s => Args(s));
As long as Args returns the same type as the queried collection type this should work okay
you can then iterate over the collection like so
foreach (var s in collection)
{
Console.WriteLine(s);
}
Related
Someone knows how to find the longest substring composed of letters using using MatchCollection.
public static Regex pattern2 = new Regex("[a-zA-Z]");
public static string zad3 = "ala123alama234ijeszczepsa";
You can loop over all matches and get the longest:
string max = "";
foreach (Match match in Regex.Matches(zad3, "[a-zA-Z]+"))
if (max.Length < match.Value.Length)
max = match.Value;
Try this:
MatchCollection matches = pattern2.Matches(txt);
List<string> strLst = new List<string>();
foreach (Match match in matches)
strLst.Add(match.Value);
var maxStr1 = strLst.OrderByDescending(s => s.Length).First();
or better way :
var maxStr2 = matches.Cast<Match>().Select(m => m.Value).ToArray().OrderByDescending(s => s.Length).First();
best solution for your task is:
string zad3 = "ala123alama234ijeszczepsa54dsfd";
string max = Regex.Split(zad3,#"\d+").Max(x => x);
You must change your Regex pattern to include the repetition operator + so that it matches more than once.
[a-zA-Z] should be [a-zA-Z]+
You can get the longest value using LINQ. Order by the match length descending and then take the first entry. If there are no matches the result is null.
string pattern2 = "[a-zA-Z]+";
string zad3 = "ala123alama234ijeszczepsa";
var matches = Regex.Matches(zad3, pattern2);
string result = matches
.Cast<Match>()
.OrderByDescending(x => x.Value.Length)
.FirstOrDefault()?
.Value;
The string named result in this example is:
ijeszczepsa
Using linq and the short one:
string longest= Regex.Matches(zad3, pattern2).Cast<Match>()
.OrderByDescending(x => x.Value.Length).FirstOrDefault()?.Value;
you can find it in O(n) like this (if you do not want to use regex):
string zad3 = "ala123alama234ijeszczepsa";
int max=0;
int count=0;
for (int i=0 ; i<zad3.Length ; i++)
{
if (zad3[i]>='0' && zad3[i]<='9')
{
if (count > max)
max=count;
count=0;
continue;
}
count++;
}
if (count > max)
max=count;
Console.WriteLine(max);
I have string pattern like this:
#c1 12,34,222x8. 45,989,100x10. 767x55. #c1
I want to change these patterns into this:
c1,12,8
c1,34,8
c1,222,8
c1,45,10
c1,989,10
c1,100,10
c1,767,55
My code in C#:
private void btnProses_Click(object sender, EventArgs e)
{
String ps = txtpesan.Text;
Regex rx = new Regex("((?:\d+,)*(?:\d+))x(\d+)");
Match mc = rx.Match(ps);
while (mc.Success)
{
txtpesan.Text = rx.ToString();
}
}
I've been using split and replace but to no avail. After I tried to solve this problem, I see many people using regex, I tried to use regex but I do not get the logic of making a pattern regex.
What should I use to solve this problem?
sometimes regex is not good approach - old school way wins. Assuming valid input:
var tokens = txtpesan.Text.Split(' '); //or use split by regex's whitechar
var prefix = tokens[0].Trim('#');
var result = new StringBuilder();
//skip first and last token
foreach (var token in tokens.Skip(1).Reverse().Skip(1).Reverse())
{
var xIndex = token.IndexOf("x");
var numbers = token.Substring(0, xIndex).Split(',');
var lastNumber = token.Substring(xIndex + 1).Trim('.');
foreach (var num in numbers)
{
result.AppendLine(string.Format("{0},{1},{2}", prefix, num, lastNumber));
}
}
var viola = result.ToString();
Console.WriteLine(viola);
And here comes a somewhat ugly regex based solution:
var q = "#c1 12,34,222x8. 45,989,100x10. 767x55. #c1";
var results = Regex.Matches(q, #"(?:(?:,?\b(\d+))(?:x(\d+))?)+");
var caps = results.Cast<Match>()
.Select(m => m.Groups[1].Captures.Cast<Capture>().Select(cap => cap.Value));
var trailings = results.Cast<Match>().Select(m => m.Groups[2].Value).ToList();
var c1 = q.Split(' ')[0].Substring(1);
var cnt = 0;
foreach (var grp in caps)
{
foreach (var item in grp)
{
Console.WriteLine("{0},{1},{2}", c1, item, trailings[cnt]);
}
cnt++;
}
The regex demo can be seen here. The pattern matches blocks of comma-separated digits while capturing the digits into Group 1, and captures the digits after x into Group 2. Could not get rid of the cnt counter, sorry.
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.
In C# what would be the best way of splitting this sort of string?
%%x%%a,b,c,d
So that I end up with the value between the %% AND another variable containing everything right of the second %%
i.e. var x = "x"; var y = "a,b,c,d"
Where a,b,c.. could be an infinite comma seperated list. I need to extract the list and the value between the two double-percentage signs.
(To combat the infinite part, I thought perhaps seperating the string out to: %%x%% and a,b,c,d. At this point I can just use something like this to get X.
var tag = "%%";
var startTag = tag;
int startIndex = s.IndexOf(startTag) + startTag.Length;
int endIndex = s.IndexOf(tag, startIndex);
return s.Substring(startIndex, endIndex - startIndex);
Would the best approach be to use regex or use lots of indexOf and substring to do the extracting based on te static %% characters?
Given that what you want is "x,a,b,c,d" the Split() function is actually pretty powerful and regex would be overkill for this.
Here's an example:
string test = "%%x%%a,b,c,d";
string[] result = test.Split(new char[] { '%', ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string s in result) {
Console.WriteLine(s);
}
Basicly we ask it to split by both '%' and ',' and ignore empty results (eg. the result between "%%"). Here's the result:
x
a
b
c
d
To Extract X:
If %% is always at the start then;
string s = "%%x%%a,b,c,d,h";
s = s.Substring(2,s.LastIndexOf("%%")-2);
//Console.WriteLine(s);
Else;
string s = "v,u,m,n,%%x%%a,b,c,d,h";
s = s.Substring(s.IndexOf("%%")+2,s.LastIndexOf("%%")-s.IndexOf("%%")-2);
//Console.WriteLine(s);
If you need to get them all at once then use this;
string s = "m,n,%%x%%a,b,c,d";
var myList = s.ToArray()
.Where(c=> (c != '%' && c!=','))
.Select(c=>c).ToList();
This'll let you do it all in one go:
string pattern = "^%%(.+?)%%(?:(.+?)(?:,|$))*$";
string input = "%%x%%a,b,c,d";
Match match = Regex.Match(input, pattern);
if (match.Success)
{
// "x"
string first = match.Groups[1].Value;
// { "a", "b", "c", "d" }
string[] repeated = match.Groups[2].Captures.Cast<Capture>()
.Select(c => c.Value).ToArray();
}
You can use the char.IsLetter to get all the list of letter
string test = "%%x%%a,b,c,d";
var l = test.Where(c => char.IsLetter(c)).ToArray();
var output = string.Join(", ", l.OrderBy(c => c));
Since you want the value between the %% and everything after in separate variables and you don't need to parse the CSV, I think a RegEx solution would be your best choice.
var inputString = #"%%x%%a,b,c,d";
var regExPattern = #"^%%(?<x>.+)%%(?<csv>.+)$";
var match = Regex.Match(inputString, regExPattern);
foreach (var item in match.Groups)
{
Console.WriteLine(item);
}
The pattern has 2 named groups called x and csv, so rather than just looping, you can easily reference them by name and assign them to values:
var x = match.Groups["x"];
var y = match.Groups["csv"];
How to split this string
1014,'0,1031,1032,1034,1035,1036',0,0,1,1,0,1,0,-1,1
and get this string array as result
1014
'0,1031,1032,1034,1035,1036'
0
0
1
1
0
1
0
-1
1
in C#
I believe that this regex should give you what you are looking for:
('(?:[^']|'')*'|[^',\r\n]*)(,|\r\n?|\n)?
http://regexr.com?2vib4
EDIT:
Quick code snippet on how it might work:
var rx = new Regex("('(?:[^']|'')*'|[^',\r\n]*)(,|\r\n?|\n)?");
var text= "1014,'0,1031,1032,1034,1035,1036',0,0,1,1,0,1,0,-1,1";
var matches = rx.Matches(text);
foreach (Match match in matches)
{
System.Console.WriteLine(match.Groups[1].ToString());
}
try this,
string line ="1014,'0,1031,1032,1034,1035,1036',0,0,1,1,0,1,0,-1,1" ;
var values = Regex.Matches(line, "(?:'(?<m>[^']*)')|(?<m>[^,]+)");
foreach (Match value in values) {
Console.WriteLine(value.Groups["m"].Value);
}
This code is not pretty at all, but it works. :) (Does not work with multiple "strings" within the string.)
void Main()
{
string stuff = "1014,'0,1031,1032,1034,1035,1036',0,0,1,1,0,1,0,-1,1";
List<string> newStuff = new List<string>();
var extract = stuff.Substring(stuff.IndexOf('\''), stuff.IndexOf('\'', stuff.IndexOf('\'') + 1) - stuff.IndexOf('\'') + 1);
var oldExtract = extract;
extract = extract.Replace(',',';');
stuff = stuff.Replace(oldExtract, extract);
newStuff.AddRange(stuff.Split(new[] {','}));
var newList = newStuff;
for(var i = 0; i < newList.Count; i++)
newList[i] = newList[i].Replace(';',',');
// And newList will be in the format you specified, but in a list..
}
Firstly split a string on ' (single) quote and then after go for comma (,).
You don't need a parser, you don't need Regex. Here's a pretty simple version that works perfectly:
var splits = input
.Split('\'')
.SelectMany(
(s,i) => (i%2==0)
? s.Split(new[]{','}, StringSplitOptions.RemoveEmptyEntries)
: new[]{ "'" + s + "'"}
);
This is exactly what #AVD + #Rawling described ... Split on ', and split only "even" results, then combine.
using System;
using System.IO;
using Microsoft.VisualBasic.FileIO; //Microsoft.VisualBasic.dll
public class Sample {
static void Main(){
string data = "1014,'0,1031,1032,1034,1035,1036',0,0,1,1,0,1,0,-1,1";
string[] fields = null;
data = data.Replace('\'', '"');
using(var csvReader = new TextFieldParser(new StringReader(data))){
csvReader.SetDelimiters(new string[] {","});
csvReader.HasFieldsEnclosedInQuotes = true;
fields = csvReader.ReadFields();
}
foreach(var item in fields){
Console.WriteLine("{0}",item);
}
}
}