C#: get the value of a key in an object using regex - c#

I have a key with random bits of string in it making it difficult to extract it's value. How would I go about doing it when I don't know the random bits ahead of time?
given:
sample = {\"total_ra4jhga987y3h_power\": 30}
Is it possible to do something directly like
dynamic obj = JsonConvert.DeserializeObject(sample);
obj[#"^total_(.*)_power$"] ---> should give me 30

Use LINQ to JSON instead. If you parse it as a JObject, you can iterate over all the properties, and find those which match your regex.
Regex regex = new Regex(...);
JObject json = JObject.Parse(text);
foreach (var property in json.Properties())
{
if (regex.IsMatch(property.Name))
{
...
}
}

var jsonDict = JsonConvert.DeserializeObject<Dictionary<string,long>>(sample);
Regex rg = new Regex("total_.*_power");
var key = jsonDict.Keys.First(k=>rg.IsMatch(k));
Console.log(jsonDict[key]);

You can utilize LINQ to go through your properties and test their names for your regexp:
public static class JsonExtensions
{
public static Dictionary<string, JToken> PropertiesByRegexp(this JObject token, Regex regex)
{
return token.Properties()
.Where(p => regex.IsMatch(p.Name))
.ToDictionary(p => p.Name, p => p.Value);
}
}
You can now use this extensions method in the following way:
JObject sample = JsonConvert.DeserializeObject("{\"total_ra4jhga987y3h_power\": 30, \"not_matching\": 31}") as JObject;
var result = sample.PropertiesByRegexp(new Regex("^total_(.*)_power$"));
foreach (var propertyPair in result)
{
Console.WriteLine($"{propertyPair.Key}: {propertyPair.Value}");
}
Outputs:
total_ra4jhga987y3h_power: 30

Related

Good approach to sorting strings which contain number ie test 1, test10, test2

I am using C#, .NET 4.7
I have 3 strings ie.
[test.1, test.10, test.2]
I need to sort them to get:
test.1
test.2
test.10
I may get other strings like
[1test, 10test, 2test]
which should produce:
1test
2test
10test
using same approach.
Thoughts?
Thanks in advance.
You could use Parse the number using Regex and then sort the string. For example,
Regex re = new Regex(#"\d+");
var result = strArray.Where(x=>re.Match(x).Success)
.Select(x=> new { Key = int.Parse(re.Match(x).Value),Value = x})
.OrderBy(x=>x.Key).Select(x=>x.Value);
Where strArray is the collection of strings.
Please note in the above case, you are ignoring string which doesn't have a numeric part (as it wasn't described in OP). The numeric part of string is parsed using Regex, which is then used for sorting the collection.
Example,
Input
var strArray = new string[]{"1test", "10test", "2test"};
Output
1test
2test
10test
Input
var strArray = new string[]{"test.1", "test.10", "test.2"};
Outpuyt
test.1
test.2
test.10
For your first array you can do
var array = new[] { "test.1", "test.10", "test.2" };
var sortedArray = array.OrderBy(s => int.Parse(s.Substring(5, s.Length - 5)));
For the second array
var array = new[] { "1test", "2test", "10test" };
var sortedArray = array.OrderBy(s => int.Parse(s.Substring(0, s.Length - 4)));
Try this code. It uses SortedDictionary which always sort it's items by key when they are inserted.
static void Main(string[] args)
{
SortedDictionary<int, string> tuples = new SortedDictionary<int, string>();
string[] stringsToSortByNumbers = { "test.1", "test.10", "test.2" };
foreach (var item in stringsToSortByNumbers)
{
int numeric = Convert.ToInt32(new String(item.Where(Char.IsDigit).ToArray()));
tuples.Add(numeric, item);
}
foreach (var item in tuples)
{
Console.WriteLine(item.Value);
}
Console.ReadKey();
}

Converting string with list of Jarray Objects to JSONin C#

I have a JSON string like
string str = [{"a":"b"},{"c":"d"}],
I converted it to Jarray with the below code,
JArray obj=JArray.Parse(str);
Its working fine, but my input string got changed to
str=[{"a":"b"},{"c":"d"}],[{"e":"f"},{"g":"h"}]
Now the JArray parsing is throwing me an error as its a list of JArray, How can i parse the above string in C#?
I was able to find a way to parse the following string using JsonReader.SupportMultipleContent:
[{"a":"b"},{"c":"d"}],[{"e":"f"},{"g":"h"}]
Thanks #dbc for pointing me in the right direction (see Additional text encountered after finished reading JSON content).
Please note that this functionality is available only from Release 11.0.1 of Json.NET.
The following method uses a JsonTextReader and returns a IEnumerable<KeyValuePair<string, string>>:
private static IEnumerable<KeyValuePair<string, string>> ParseKeyValuePairs(string json)
{
using (var reader = new StringReader(json))
using (var jsonReader = new JsonTextReader(reader) { SupportMultipleContent = true })
{
JsonSerializer serializer = JsonSerializer.CreateDefault();
while (jsonReader.Read())
{
if (jsonReader.TokenType == JsonToken.Comment)
{
continue;
}
var dictionaries = serializer.Deserialize<List<Dictionary<string, string>>>(jsonReader);
foreach (KeyValuePair<string, string> keyValue in dictionaries.SelectMany(x => x))
{
yield return keyValue;
}
}
}
}
Using the code to generate a Dictionary<string, string>:
string json = #"[{""a"":""b""},{""c"":""d""}],[{""e"":""f""},{""g"":""h""}]";
Dictionary<string, string> data = ParseKeyValuePairs(json).ToDictionary(x => x.Key, x => x.Value);
Result:

String parsing (splitting and retrieving parameters)

I have a string formatted this way:
<?TAG param1="val1" parm2="val2" paramN="valN" /><?TAG param1="val1" parm2="val2" paramN="valN"/><?TAG param1="val1" parm2="val2" paramN="valN"/>
"TAG" is always the same value, but number of occurrences is variable and the number of parameters for each occurrence too. I can't change the source format.
I need to get the list of parameters for each occurrence using C# (.NET 4.0) Can you help me out?
XElement rootElement = XElement.Parse(string.Format("<element>{0}</element>",
yourString.Replace("?TAG", "TAG")));
var elements = rootElement.Elements();
var yourResult = elements.Select(x => new TagsAndParams { Tag = x,
Params = x.Attributes.Where(xa => xa.Name.LocalName.BeginsWith("param") });
With this class as a result holder (I know I could use anonymous types, but this is better for passing to other functions):
public class TagsAndParams
{
XElement Tag;
IEnumerable<XAttribute> Params;
}
You could do it with a nasty looking RegEx, but I'd make sure it's not actually an XML PI chain first:
(?<tag><?TAG (?<parm>param\d{1,2}=\"[^\"]+\"\s*)*\/\>)*
This will match groups, each group containing:
full tag
paramX="valX" pair
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
class ExampleClass
{
static void Main(string[] args)
{
string example = "<?TAG param1=\"val1\" param2=\"val2\" paramN=\"valN\" /><?TAG param1=\"val1\" param2=\"val2\" paramN=\"valN\"/><?TAG param1=\"val1\" param2=\"val2\" paramN=\"valN\"/>";
List<Dictionary<string, string>> result = new List<Dictionary<string, string>>();
string[] tokens = Regex.Split(example, "/><\\?TAG|<\\?TAG|/>");
foreach (string token in tokens) if (token.Length > 0)
{
Dictionary<string, string> parameters = new Dictionary<string, string>();
string[] parms = token.Split(' ');
foreach (string parm in parms) if (parm.Length > 0)
{
string[] keyvalue = Regex.Split(parm, "=\"|\"");
parameters.Add(keyvalue[0], keyvalue[1]);
}
result.Add(parameters);
}
Console.WriteLine("TAGs detected: " + result.Count);
foreach (Dictionary<string, string> token in result)
{
Console.WriteLine("TAG");
foreach (KeyValuePair<string, string> kvp in token)
Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
}
}
}
I've finally solved using this code (provided by a friend of mine). The trick was the Regex used for splitting individual elements. Thank you for the support, I will make use of the tip about xml parser in future :)

c# - regex to find a string that comes after = [duplicate]

This question already has answers here:
regex to find a string that comes after =
(6 answers)
Closed 9 years ago.
So I asked this question before and said I wanted it in javascript but realized later on that it's unecessary data being sent. So it would be great if anybody could help me solve the same thing in C#
What I need is to get several properties out of a string.
The string will look something like:
str = "car[brand=saab][wheels=4]";
There can be more or fewer properties.
I need everything before the first [] in 1 variable.
Then I need each property and its value in a variable.
Easiest way to understand what I want is probably to check my previous question and the answer that solved it :)
I used the regex(slightly different) in your previous question.
string input = "car[brand=saab][wheels=4]";
string product = "";
Dictionary<string, string> props = new Dictionary<string, string>();
foreach (Match m in Regex.Matches(input, #"^(\w+)|\[(\w+)=(.+?)\]"))
{
if (String.IsNullOrEmpty(product))
product = m.Groups[1].Value;
else
props.Add(m.Groups[2].Value, m.Groups[3].Value);
}
try this regex:
(.+?)(\[.+?\])+
and a sample code:
var inputString = "car[brand=saab][wheels=4]";
var pattern = #"(?<v1>.+?)(?<v2>\[.+?\])+";
var v1 = Regex.Match(inputString, pattern).Groups["v1"].Value;
Dictionary<String, String> list = new Dictionary<String, String>();
foreach (Capture capture in Regex.Match(inputString, pattern).Groups["v2"].Captures)
{
var sp = capture.Value.Split('=');
list.Add(sp[0], sp[1]);
}
explain:
(?<name>subexpression)
Captures the matched subexpression into a named group.
You can do this
var lst=Regex.Matches(input,#"(\w+)((?:\[.*?\])+)")
.Cast<Match>()
.Select(x=>new
{
name=x.Groups[1].Value,
value=Regex.Matches(x.Groups[2].Value,#"(?<=\[).*?(?=\])")
.Cast<Match>()
.Select(x=>new
{
name=x.Groups[0].Value.Split('=')[0],
value=x.Groups[0].Value.Split('=')[1]
})
});
Now you can iterate over lst like this
foreach(var parent in lst)
{
parent.name;//car
foreach(var pairs in parent.value)
{
pairs.name;//brand,wheels
pairs.value;//ferrari,4
}
}
So,for input car[brand=a][wheels=4]cycle[brand=b][wheels=2]
Output would be like
car
brand,a
wheels,4
cycle
brand,b
wheels,2
Without regex:
string input = "car[brand=saab][wheels=4]";
var query = from s in input.Replace("]", "").Split('[')
let vars = s.Split('=')
let name = vars[0]
let value = vars.Length > 1 ? vars[1] : ""
select new {Name = name, Value = value};
string firstVar = query.First().Name;
Dictionary<string, string> otherVars = query
.Skip(1)
.ToDictionary(v => v.Name, v => v.Value);
You can access your variables in the dictionary like this string brand = otherVars["brand"]
Since you already have an answer using regex and your comments state it doesn't have to be with a regex, I'll offer an alternative:
The code is
string str = ("car[brand=saab][wheels=4]");
int i = str.IndexOf("[");
string[] details =str.Substring(i).Replace("]","").Split('[');
string name = str.Substring(0, i);
string brand = details[1].Split('=')[1];
string wheels = details[2].Split('=')[1];
This approach assumes the data is always going to be in the same format though; you may need some validation in there depending on your needs...

How can you change a ";" seperated string to some kind of dictionary?

I have a string like this:
"user=u123;name=Test;lastname=User"
I want to get a dictionary for this string like this:
user "u123"
name "Test"
lastname "User"
this way I can easely access the data within the string.
I want to do this in C#.
EDIT:
This is what I have so far:
public static Dictionary<string, string> ValueToDictionary(string value)
{
Dictionary<string, string> result = null;
result = new Dictionary<string, string>();
string[] values = value.Split(';');
foreach (string val in values)
{
string[] valueParts = val.Split('=');
result.Add(valueParts[0], valueParts[1]);
}
return result;
}
But to be honest I really think there is a better way to do this.
Cheers,
M.
You can use LINQ:
var text = "user=u123;name=Test;lastname=User";
var dictionary = (from t in text.Split( ";".ToCharArray() )
let pair = t.Split( "=".ToCharArray(), 2 )
select pair).ToDictionary( p => p[0], p => p[1] );
Split the string by ";".
Iterate over every element in the resulting array and split every element by "=".
Now;
dictionary.add(element[0], element[1]);
I Hope I made it clear enough.
Dictionary<string, string> d = new Dictionary<string, string>();
string s1 = "user=u123;name=Test;lastname=User";
foreach (string s2 in s1.Split(';'))
{
string[] split = s2.Split('=');
d.Add(split[0], split[1]);
}
var dictionary = new Dictionary<string, string>();
var linedValue = "user=u123;name=Test;lastname=User";
var kvps = linedValue.Split(new[] { ';' }); // you may use StringSplitOptions.RemoveEmptyEntries
foreach (var kvp in kvps)
{
var kvpSplit = kvp.Split(new[] { '=' });
var key = kvpSplit.ElementAtOrDefault(0);
var value = kvpSplit.ElementAtOrDefault(1);
dictionary.Add(key, value);
// you may check with .ContainsKey if key is already persistant
// you may check if key and value with string.IsNullOrEmpty
}
If you know for sure that there are no separator chars in your input data, the following works
string input = "user=u123;name=Test;lastname=User";
string[] fragments = input.Split(";=".ToArray());
Dictionary<string,string> result = new Dictionary<string,string>()
for(int i=0; i<fragments.Length-1;i+=2)
result.Add(fragments[i],fragments[i+1]);
It might perform slightly better than some of the other solutions, since it only calls Split() once. Usually I would go for any of the other solutions here, especially if readability of the code is of any value to you.
I think I would do it like this...
String s = "user=u123;name=Test;lastname=User";
Dictionary<string,string> dict = s.ToDictionary();
The implementation of ToDictonary is the same as yours except that I would implement it as an extension method. It does look more natural.

Categories