Substring continue to search until specific character - c#

I am getting a string at the run time. The string is in JSON format( key value pair). One of the key is "userId". I need to retrieve the value of userId. The problem is I don't know the position of "userId" key. The string can look like {"name":"XX", "userId":"YYY","age":"10"} or it can look like {"age":"10", "name":"XX", "userId":"YYY"} or it can look like this {"age":"10"}
I am thinking of using substring()
var index = myString.IndexOf("userId\":\"");
if(index != -1){
myString.Subtring(index, ???)//How to specify the length here
}
I am not sure, how to say continue until you find next " (double quote)

If only userId attribute is planned to use, you can simply declare an object with userId member and deserialize json. any other attributes will be omitted during deserialization.
class UserIDObj
{
public string UserId { get; set; }
}
var obj = JsonConvert.DeserializeObject<UserIDObj>("{\"name\":\"XX\", \"userId\":\"YYY\",\"age\":\"10\"}");
string usrID = obj.UserId;

Answer given by #Wiktor Stribiżew also works like a charm. I am pasting his solution.
System.Text.RegularExpressions.Regex.Match(myString, "\"userId\":\"([^\"]+)").Groups[1].Value

You could do this:
var needle = "\"userId\":"; // also you forgot to escape the quote here
var index = myString.IndexOf(needle);
if(index != -1){
var afterTheUserId = myString.Substring(index + needle.Length);
var quoteIndex = afterTheUserId.IndexOf('"');
// do what you want with quoteIndex
}
But as Eric Philips and PhonicUK said, you should use a proper JSON parser instead of writing your own string functions.

Related

How do i split a value in model class

How do i split a value in model class.
in list[0].key = 1 and list[0].value = 1_5
here is the code:
if (data.Things.Count != 0)
{
var ans = new List<QuestionModel>();
ans = data.Things.Select(item =>
{
return new QuestionModel()
{
QuestionId = Convert.ToInt32(item.Key),
AnswerId = Convert.ToInt32(item.Value),
};
}).ToList();
}
here i want to split the value.i.e. in AnswerId want only 5.
If you always want the part after the underscore, and it's always an underscore in the format of item.Value, you can do this:
item.Value.Split('_')[1];
This splits the string on the _ and then takes the second part (e.g. what is after the _).
So the complete line of code would be:
AnswerId = Convert.ToInt32(item.Value.Split('_')[1]),
I would add that the fact you are having to do something this clunky is perhaps a symptom of your model not being a good fit to your domain - if you are able to refactor your model such that you don't have to do this and the field in question contains only the data you are interested in then your solution would be cleaner and more easily maintainable.
Come on. Value is a string value right? Did you look at string class what methods does it have? There is a method called split. Read more here: https://msdn.microsoft.com/en-US/library/b873y76a(v=vs.110).aspx
In short:
string value = "1_5";
string[] arr = value.Split('_');
//now arr[0] is "1" and arr[1] is "5"
int i = Convert.ToInt(arr[1]);
I'm not entirely sure, what you're trying to achieve, but I think you want to split the string "1_5" and retrieve just the "5". This can be achieved using string.Split():
(item.Value.Split('_'))[1]

Round-trip-safe escaping of strings in C#

I am confused by all the different escaping mechanisms for strings in C#. What I want is an escaping/unescaping method that:
1) Can be used on any string
2) escape+unescape is guaranteed to return the initial string
3) Replaces all punctuation with something else. If that is too much to ask, then at least commas, braces, and #. I am fine with spaces not being escaped.
4) Is unlikely to ever change.
Does it exist?
EDIT: This is for purposes of seriliazing and deserializing app-generated attributes. So my object may or may not have values for Attribute1, Attribute2, Attribute3, etc. Simplifying a bit, the idea is to do something like the below. Goal is to have the encoded collection be brief and more-or-less human-readable.
I am asking what methods would make sense to use for Escape and Unescape.
public abstract class GenericAttribute {
const string key1 = "KEY1"; //It is fine to put some restrictions on the keys, i.e. no punctuation
const string key2 = "KEY2";
public abstract string Encode(); // NO RESTRICTIONS ON WHAT ENCODE MIGHT RETURN
public static GenericAttribute FromKeyValuePair (string key, string value) {
switch (key) {
case key1: return new ConcreteAttribute1(value);
case key2: return new ConcreteAttribute2(value);
// etc.
}
}
}
public class AttributeCollection {
Dictionary <string, GenericAttribute> Content {get;set;}
public string Encode() {
string r = "";
bool first = true;
foreach (KeyValuePair<string, GenericAttribute> pair in this.Content) {
if (first) {
first = false;
} else {
r+=",";
}
r+=(pair.Key + "=" + Escape(pair.Value.Encode()));
}
return r;
}
public AttributeCollection(string encodedCollection) {
// input string is the return value of the Encode method
this.Content = new Dictionary<string, GenericAttribute>();
string[] array = encodedCollection.Split(',');
foreach(string component in array) {
int equalsIndex = component.IndexOf('=');
string key = component.Substring(0, equalsIndex);
string value = component.Substring(equalsIndex+1);
GenericAttribute attribute = GenericAttribute.FromKeyValuePair(key, Unescape(value));
this.Content[key]=attribute;
}
}
}
I'm not entirely sure what your asking, but I believe your intent is for the escaped character to be included, even with the escape.
var content = #"\'Hello";
Console.WriteLine(content);
// Output:
\'Hello
By utilizing the # it will include said escaping, making it apart of your string. That is for the server-side with C#, to account for other languages and escape formats only you would know that.
You can find some great information on C# escaping here:
MSDN Blog
Try using HttpServerUtility.UrlEncode and HttpServerUtility.UrlDecode. I think that will encode and decode all the things you want.
See the MSDN Docs and here is a description of the mapping on Wikipedia.

Grab only part of the string at dynamic location

I have string file with content like this
string a = "12,1,______,_,__;1,23,122;"
I want to grab only this integer value 23. Problem is that this conntent is dynamic and I it's lenght can be changed, so this string a can easily be in the next iteration like
string a = "12,1,______,_,__;11,2,1;"
In this case I would grab integer 2.
If the structure is always the same, then:
Split the string, and grab the element before last.
var array1 = a.Split(';');
// check the array length if it's needed to avoid
// IndexOutOfRangeException exception
var array2 = array1[1].Split(',');
var yourNumber = array2[array2.Length - 2]
String.Split
Ignoring error checking for a minute, this would work:
string a = "12,1,______,_,__;11,2,1;"
int i = Int32.Parse(String.Split(',')[5])
If this is the route you will go, you should take extra care to verify your input. Check the length of the array reutrned from Split, and verify that the 5th value can indeed be parsed to an int.
Try this regex:
(?<=;\d*,)\d*(?=,\d*;)
Sample usage:
class Program
{
static void Main(string[] args)
{
string a = "12,1,______,_,__;1,23,122;";
var regex = new Regex(#"(?<=;\d*,)\d*(?=,\d*;)");
Console.WriteLine(regex.Match(a).Value);
a = "12,1,______,_,__;11,2,1;";
Console.WriteLine(regex.Match(a).Value);
}
}
Try this:
var number = a.split(",")[5];
another option is to split the text into array (if they have same pattern):
var output = a.Split(",;".ToCharArray());
var value = output[theIndex]; // get the index you want

Replace Variables in String?

I am Searching though the contents of a Excel Spreadsheet template at replacing all the variables represented by #Something.
I have all the variables names come up with code, i'm just looking for a way to replace the them in a string.
Example:
My name is #Name
I want it to become:
My name is John.
My Code explained:
I have an array holding a struct which holds:
TagPointer: this is my variable #name,
TagValue: this would be the name John
Here i can get the index of where my variable is and i have the original String its Comp.
I am just unsure how i can replace the #Something.
int testnum;
if (Comp != "null")
{
if (Comp.IndexOf(ArrayNode[i].TagPointer) != -1)
{
testnum = Comp.IndexOf(ArrayNode[i].TagPointer);
}
}
use string.Format(), string.Replace() there is less convenient
string value = "John";
string result = string.Format("My name is {0}", value);
Unless I'm missing something, can't you use the string.replace function?
You could do something like:
foreach (var tag in ArrayNode)
{
Comp = Comp.Replace(tag.TagPointer, tag.TagValue);
}
Have you ever seen the FormatWith extension?
With it you can write something like this:
Status.Text = "{UserName} last logged in at {LastLoginDate}".FormatWith(user);
Why not using
ie
string name = "Giusepe";
string _tmp = "My name is #Name";
_tmp = _tmp.Replace("#Name", name);
You could iterate over your array and use the .Contains() to see which tag you have present and use the .Replace() to replace the tag with the actual value.
Do you want this:
string a = "#Something";
a = a.Replace("#somethig", Value);
?
Years later, we now have string interpolation to help with this.

string manipulation check and replace with fastest method

I have some strings like below:
string num1 = "D123_1";
string num2 = "D123_2";
string num3 = "D456_11";
string num4 = "D456_22";
string num5 = "D_123_D";
string num5 = "_D_123";
I want to make a function that will do the following actions:
1- Checks if given string DOES HAVE an Underscore in it, and this underscore should be after some Numbers and Follow with some numbers: in this case 'num5' and 'num6' are invalid!
2- Replace the numbers after the last underscore with any desired string, for example I want 'num1 = "D123_1"' to be changed into 'D123_2'
So far I came with this idea but it is not working :( First I dont know how to check for criteria 1 and second the replace statement is not working:
private string CheckAndReplace(string given, string toAdd)
{
var changedString = given.Split('_');
return changedString[changedString.Length - 1] + toAdd;
}
Any help and tips will be appriciated
What you are looking for is a regular expression. This is (mostly) from the top of my head. But it should easily point you in the right direction. The regular expression works fine.
public static Regex regex = new Regex("(?<character>[a-zA-Z]+)(?<major>\\d+)_(?<minor>\\d+)",RegexOptions.CultureInvariant | RegexOptions.Compiled);
Match m = regex.Match(InputText);
if (m.Succes)
{
var newValue = String.Format("{0}{1}_{2}"m.Groups["character"].Value, m.Groups["major"].Value, m.Groups["minor"].Value);
}
In your code you split the String into an array of strings and then access the wrong index of the array, so it isn't doing what you want.
Try working with a substring instead. Find the index of the last '_' and then get the substring:
private string CheckAndReplace(string given, string toAdd) {
int index = given.LastIndexOf('_')+1;
return given.Substring(0,index) + toAdd;
}
But before that check the validity of the string (see other answers). This code fragment will break when there's no '_' in the string.
You could use a regular expression (this is not a complete implementation, only a hint):
private string CheckAndReplace(string given, string toAdd)
{
Regex regex = new Regex("([A-Z]*[0-9]+_)[0-9]+");
if (regex.IsMatch(given))
{
return string.Concat(regex.Match(given).Groups[1].Value, toAdd);
}
else
{
... do something else
}
}
Use a good regular expression implementation. .NET has standard implementation of them

Categories