Split json alike string by regex expression - c#

I would like to split the string below by using regex expression
Country:Subdivision, Level1:{Level2a:{Level3a, Level3b}, Level2b}
into form of
Country
Subdivision
Level1
Level2a
Level3a
Level3b
Level2b
I knew there will be a recursive function to split to string into the above form.
I'm using .net, and want to split to string into a class
public class ListHierarchy
{
public string Name { get; set; }
public ListHierarchy ParentListHierarchy { get; set; }
}
The concept as below (Output):
var list1 = new ListHierarchy() { Name = "Country" };
var list2 = new ListHierarchy() { Name = "Subdivision", ParentListHierarchy = list1 };
var list3 = new ListHierarchy() { Name = "Level1" };
var list4 = new ListHierarchy() { Name = "Level2a", ParentListHierarchy = list3 };
var list5 = new ListHierarchy() { Name = "Level2b", ParentListHierarchy = list3 };
var list6 = new ListHierarchy() { Name = "Level3a", ParentListHierarchy = list4 };
var list7 = new ListHierarchy() { Name = "Level3b", ParentListHierarchy = list4 };
Guys, I have to solution already, but still need to fine tune on the regex
public static Dictionary<string, string> SplitToDictionary(string input, string regexString)
{
Regex regex = new Regex(regexString);
return regex.Matches(input).Cast<Match>().ToDictionary(x => x.Groups[1].Value.Trim(), x => x.Groups[2].Value.Trim());
}
string input = "Country:Subdivision, Level1:{Level2a:{Level3a:Level4a, Level3b}, Level2b}";
var listHierarchy = new List<ListHierarchy>();
Dictionary<string, string> listParent = SplitToDictionary(input, #"([\w\s]+):(([\w\s]+)|([\w\s\,\{\}\:]+))");
but, i getting
{Level2a:{Level3a, Level3b}, Level2b}
rather than
Level2a:{Level3a, Level3b}, Level2b

I love regular expressions, but for this problem they are just not the right tool.
Irony is an awesome and very easy to use library that will let you write a parser for your json-like thing.
It's free, open source, and the examples include a json parser that you can adapt to your needs.

you can use this regex
([^\s,:{}])+
This would get you the Country Subdivision Level1 Level2a Level3a Level3b Level2b.
you would have to put it into an array and then push it out according to your style.
EDIT
This would actively destroy the JSON hierarchy therefore is not recommended to be used for this question/situation. This would only return strings that can be stored in an array.

Related

.NET 6 “core” Create Dynamic Object containing List<MyOtherDynamicListObject> [duplicate]

For some of my unit tests I want the ability to build up particular JSON values (record albums in this case) that can be used as input for the system under test.
I have the following code:
var jsonObject = new JObject();
jsonObject.Add("Date", DateTime.Now);
jsonObject.Add("Album", "Me Against The World");
jsonObject.Add("Year", 1995);
jsonObject.Add("Artist", "2Pac");
This works fine, but I have never really like the "magic string" syntax and would prefer something closer to the expando-property syntax in JavaScript like this:
jsonObject.Date = DateTime.Now;
jsonObject.Album = "Me Against The World";
jsonObject.Year = 1995;
jsonObject.Artist = "2Pac";
Well, how about:
dynamic jsonObject = new JObject();
jsonObject.Date = DateTime.Now;
jsonObject.Album = "Me Against the world";
jsonObject.Year = 1995;
jsonObject.Artist = "2Pac";
You can use the JObject.Parse operation and simply supply single quote delimited JSON text.
JObject o = JObject.Parse(#"{
'CPU': 'Intel',
'Drives': [
'DVD read/writer',
'500 gigabyte hard drive'
]
}");
This has the nice benefit of actually being JSON and so it reads as JSON.
Or you have test data that is dynamic you can use JObject.FromObject operation and supply a inline object.
JObject o = JObject.FromObject(new
{
channel = new
{
title = "James Newton-King",
link = "http://james.newtonking.com",
description = "James Newton-King's blog.",
item =
from p in posts
orderby p.Title
select new
{
title = p.Title,
description = p.Description,
link = p.Link,
category = p.Categories
}
}
});
Json.net documentation for serialization
Neither dynamic, nor JObject.FromObject solution works when you have JSON properties that are not valid C# variable names e.g. "#odata.etag". I prefer the indexer initializer syntax in my test cases:
JObject jsonObject = new JObject
{
["Date"] = DateTime.Now,
["Album"] = "Me Against The World",
["Year"] = 1995,
["Artist"] = "2Pac"
};
Having separate set of enclosing symbols for initializing JObject and for adding properties to it makes the index initializers more readable than classic object initializers, especially in case of compound JSON objects as below:
JObject jsonObject = new JObject
{
["Date"] = DateTime.Now,
["Album"] = "Me Against The World",
["Year"] = 1995,
["Artist"] = new JObject
{
["Name"] = "2Pac",
["Age"] = 28
}
};
With object initializer syntax, the above initialization would be:
JObject jsonObject = new JObject
{
{ "Date", DateTime.Now },
{ "Album", "Me Against The World" },
{ "Year", 1995 },
{ "Artist", new JObject
{
{ "Name", "2Pac" },
{ "Age", 28 }
}
}
};
There are some environment where you cannot use dynamic (e.g. Xamarin.iOS) or cases in where you just look for an alternative to the previous valid answers.
In these cases you can do:
using Newtonsoft.Json.Linq;
JObject jsonObject =
new JObject(
new JProperty("Date", DateTime.Now),
new JProperty("Album", "Me Against The World"),
new JProperty("Year", "James 2Pac-King's blog."),
new JProperty("Artist", "2Pac")
)
More documentation here:
http://www.newtonsoft.com/json/help/html/CreatingLINQtoJSON.htm
Sooner or later you will have property with a special character. e.g. Create-Date. The hyphen won't be allowed in property name. This will break your code. In such scenario, You can either use index or combination of index and property.
dynamic jsonObject = new JObject();
jsonObject["Create-Date"] = DateTime.Now; //<-Index use
jsonObject.Album = "Me Against the world"; //<- Property use
jsonObject["Create-Year"] = 1995; //<-Index use
jsonObject.Artist = "2Pac"; //<-Property use
Simple way of creating newtonsoft JObject from Properties.
This is a Sample User Properties
public class User
{
public string Name;
public string MobileNo;
public string Address;
}
and i want this property in newtonsoft JObject is:
JObject obj = JObject.FromObject(new User()
{
Name = "Manjunath",
MobileNo = "9876543210",
Address = "Mumbai, Maharashtra, India",
});
Output will be like this:
{"Name":"Manjunath","MobileNo":"9876543210","Address":"Mumbai, Maharashtra, India"}
May I suggest using the nameof expression combined with a model for the structure you're trying to build?
Example:
record RecordAlbum(string Album, string Artist, int Year);
var jsonObject = new JObject
{
{ nameof(RecordAlbum.Album), "Me Against The World" },
{ nameof(RecordAlbum.Artist), "2Pac" },
{ nameof(RecordAlbum.Year), 1995 }
};
As an added benefit to removing the "magic string" aspect - this also will give you a little bit of refactor-ability. You can easily rename any given property name for the record and it should update the value returned by the nameof() expression.
You can use Newtonsoft library and use it as follows
using Newtonsoft.Json;
public class jb
{
public DateTime Date { set; get; }
public string Artist { set; get; }
public int Year { set; get; }
public string album { set; get; }
}
var jsonObject = new jb();
jsonObject.Date = DateTime.Now;
jsonObject.Album = "Me Against The World";
jsonObject.Year = 1995;
jsonObject.Artist = "2Pac";
System.Web.Script.Serialization.JavaScriptSerializer oSerializer =
new System.Web.Script.Serialization.JavaScriptSerializer();
string sJSON = oSerializer.Serialize(jsonObject );

C# Get biggest number from a field in a list of objects

I have a list with this structure:
public class Amendment{
public string name
public string groupnumber
public string edition
public string destination
}
The data is as follows
var amendmentOne = new Amendment{
name = "Apple",
groupnumber = "A12345",
edition = "A55600E01"
phonenumber = "2232132123"
}
var amendmentTwo = new Amendment{
name = "Apple",
groupnumber = "AG2222",
edition = "A55600E02"
phonenumber = "2232132123"
}
var amendmentThree = new Amendment{
name = "Apple",
groupnumber = "AG55555",
edition = "A55600E03"
phonenumber = "2232132123"
}
Is it possible to somehow get the list item with edition number A55600E03 from the list when I loop through it? The edition numbers are all the same except for the last few characters as they will always be E[number]
Should be as easy as
var result = List.Orderby(x => edition).Last();
Example
var list = new List<Amendment>{amendmentThree, amendmentOne, amendmentTwo};
var result = list.OrderBy(x => x.edition).Last();
Console.WriteLine(result.edition);
Output
A55600E03
Full Demo Here

Elastic search with Nest

I am working on below code, and what I want to do is query by object itself.
For example: I have a search form, that populates objects fields such as below. Then what I want to do is to search Elastic search based on whatever user filled the form with.
ie: below, I want to query the index by searchItem object. How can I do it easily?
class Program
{
static void Main(string[] args)
{
var p = new Program();
var item1 = new Announcement() {Id=1, Title = "john", ContentText = "lorem", Bar = false, Num = 99, Foo = "hellow"};
//p.Index(item1, "add");
var searchItem = new Announcement() {Title="john",Num=99};
ElasticClient.Search<Announcement>();
Console.Read();
}
public void Index(Announcement announcement, String operation)
{
var uriString = "http://localhost:9200";
var searchBoxUri = new Uri(uriString);
var settings = new ConnectionSettings(searchBoxUri);
settings.SetDefaultIndex("test");
var client = new ElasticClient(settings);
if (operation.Equals("delete"))
{
client.DeleteById("test", "announcement", announcement.Id);
}
else
{
client.Index(announcement, "test", "announcement", announcement.Id);
}
}
private static ElasticClient ElasticClient
{
get
{
try
{
var uriString = "http://localhost:9200";
var searchBoxUri = new Uri(uriString);
var settings = new ConnectionSettings(searchBoxUri);
settings.SetDefaultIndex("test");
return new ElasticClient(settings);
}
catch (Exception)
{
throw;
}
}
}
}
You can't :)
NEST cannot infer how to best query only based on a partially filled POCO. Should it OR or AND should it do a nested term query or a term query wrapped in a has_child? You catch my drift.
Nest does have a slick feature called conditionless queries that allow you the write out to entire query like so:
ElasticClient.Search<Announcement>(s=>s
.Query(q=>
q.Term(p=>p.Title, searchItem.Title)
&& q.Term(p=>p.Num, searchItem.Num)
//Many more queries use () to group all you want
)
)
When NEST sees that the argument passed to Term is null or empty it simply wont render that part of the query.
Read more here on how this feature works http://nest.azurewebsites.net/concepts/writing-queries.html

c# find keywords in a list and create new list from the found items

i am learning c# and have the following problem, i can not find a solution.
the code i am trying is:
string theString = "aaa XXX,bbb XXX,ccc XXX,aaa XXX";
List<string> listFromTheString= new List<string>(theString.Split(','));
List<string> listOfFoundItems = new List<string>();
for (int i = 0; i < (listFromTheString.Count); i++)
{
if(listFromTheString[i].Contains("aaa"))
{
listOfFoundItems.Add(listFromTheString[i]);
}
}
I would like to iterate through the list and create new items in a new list if a special keyword is found. The list listOfFoundItems does not get filled with the founds.
can you please give me a hint what i am doing wrong?
You can accomplish this more succinctly with LINQ:
string theString = ("aaa XXX,bbb XXX,ccc XXX,aaa XXX");
List<string> listFromTheString = new List<string>(theString.Split(','));
List<string> listOfFoundItems = listFromTheString.Where(s => s.Contains("aaa")).ToList();
The code you provided does work, though.
Here's an alternate, one-line version:
List<string> listOfFoundItems = theString.Split(',').Where(s => s.Contains("aaa")).ToList();
theString.Split(',').Where(p=>p.Contains("aaa")).ToList()
I know you want to fix your algorithm, but once you do, consider grokking this expression:
listofFoundItems = (from s in theString.Split(',')
where s.Contains("aaa")
select s).ToList();
The code you provide works fine. Given that, I suspect you may be having some string comparison issues.
This code may work better for you:
const string given = "aaa XXX,bbb XXX,ccc XXX,aaa XXX";
var givenSplit = new List<string>(given.Split(','));
var listOfFoundItems = new List<string>();
foreach(var item in givenSplit.Where(g => g.IndexOf("aAa", StringComparison.InvariantCultureIgnoreCase) > -1))
{
listOfFoundItems.Add(item);
}
// two items are added
string theString = ("aaa XXX,bbb XXX,ccc XXX,aaa XXX");
List<string> listFromTheString = new List<string>(theString.Split(','));
List<string> listOfKeywords = new List<string> { "aaa" };
List<string> found = (from str in listFromTheString
where listOfKeywords.Any(keyword => str.Contains(keyword))
select str).ToList<string>();

Searching item in List

person[] prn =
new person[]
{
new person { Name = "Robert", RList =
{new ReceipeList { NameofRecipie = "Coak" },
new ReceipeList { NameofRecipie = "Pizza" } } },
new person { Name = "Rahim", RList =
{ new ReceipeList { NameofRecipie = "Coak" },
new ReceipeList { NameofRecipie = "OnionBread" }} },
};
When searching an item
ReceipeList lstr = new ReceipeList();
lstr.NameofRecipie = "Coak";
using
var query = from lst in prn where(lst.RList.Contains(lstr) ) select lst;
it did not return any result.
foreach (var v in query)
{
Console.Write(v.Name.ToString()+" ordered :");
foreach(ReceipeList lst in v.RList)
{
Console.Write(lst.NameofRecipie.ToString()+",");
}
Console.WriteLine();
}
This isn't working because you're searching for a specific instance of ReceipeList (by reference). Because of this, your query will only return values that have your specific lstr instance of ReceipeList, not a ReceipeList with the same value as the one you're specifying.
You could make this work by overriding Equals in ReceipeList, or by reworking your query to:
string lstr = "Coak";
var query = from lst in prn
where lst.RList.Any(r => r.NameofRecipie == lstr)
select lst;
This works because it uses the Any() method to search the ReceipeList instances by a predicate, instead of searching for a specific instance.
Im Not sure if, but you can look at this also, might help a little bit?

Categories