Changing the middle of a string - c#

I have a list of strings.. each one looks similar to this:
"\n\t\"BLOCK\",\"HEADER-\"\r\n\t\t\"NAME\",\"147430\"\r\n\t\t\"REVISION\",\"0000\"\r\n\t\t\"DATE\",\"11/11/10\"\r\n\t\t\"TIME\",\"10:03:47\"\r\n\t\t\"PMABAR\",\"\"\r\n\t\t\"COMMENT\",\"\"\r\n\t\t\"PTPNAME\",\"0805C\"\r\n\t\t\"CMPNAME\",\"0805C\"\r\n\t\"BLOCK\",\"PRTIDDT-\"\r\n\t\t\"PMAPP\",1\r\n\t\t\"PMADC\",0\r\n\t\t\"ComponentQty\",4\r\n\t\"BLOCK\",\"PRTFORM-\"\r\n\t\t\....(more)...."
What I am trying to do is keep that entire string BUT... replace the DATE, TIME and ComponentQty.....
I want to place the date variable that i have set for the DATE, as well as the DateTime.Now.ToString(""HH:mm:ss") for the TIME ... and a dictionary[part] for the ComponentQty. These values would replace like so:
"DATE","11/11/10" with "DATE","12/06/11"
"TIME","10:03:47" with "TIME","10:30:10"
"ComponentQty",4 with "ComponentQty", 8
or something similar...
so the new string would look like this:
"\n\t\"BLOCK\",\"HEADER-\"\r\n\t\t\"NAME\",\"147430\"\r\n\t\t\"REVISION\",\"0000\"\r\n\t\t\"DATE\",\"12/06/11\"\r\n\t\t\"TIME\",\"10:30:10"\"\r\n\t\t\"PMABAR\",\"\"\r\n\t\t\"COMMENT\",\"\"\r\n\t\t\"PTPNAME\",\"0805C\"\r\n\t\t\"CMPNAME\",\"0805C\"\r\n\t\"BLOCK\",\"PRTIDDT-\"\r\n\t\t\"PMAPP\",1\r\n\t\t\"PMADC\",0\r\n\t\t\"ComponentQty\",8\r\n\t\"BLOCK\",\"PRTFORM-\"\r\n\t\t\....(more)...."
What is the quickest way to do such a thing? I was thinking Regex but I am not too sure on how to go about doing this. Can anyone help?
EDIT:
I used just a normal string replace to do it.. but the replaced data will not always have the statc date, time, compQty that I have below (11/11/10, 10:03:47, 4)... I need to find a way to make that section not hard coded -- with regex I am assuming..
var newDate = "DATE\",\"" + date + "\"";
var newTime = "TIME\",\"" + DateTime.Now.ToString("HH:mm:ss") + "\"";
var newCompQTY = "ComponentQty\"," + dictionary[part];
trimmedDataBasePart = trimmedDataBasePart.ToUpper().Replace("DATE\",\"11/11/10", newDate);
trimmedDataBasePart = trimmedDataBasePart.ToUpper().Replace("TIME\",\"10:03:47", newTime);
trimmedDataBasePart = trimmedDataBasePart.ToUpper().Replace("COMPONENTQTY\",4", newCompQTY);
I am trying to set a value to a Regex and am not sure how to do so... this is what I was trying... but it obviously does not work because the var is not a string. any suggestions?
var newDate = "DATE\",\"" + date + "\"";
var regexedDate = Regex.Match(trimmedDataBasePart, "DATE\",[0-9]+/[0-9]+/[0-9]+");
trimmedDataBasePart = trimmedDataBasePart.ToUpper().Replace(regexedDate, newDate);

Try this:
resultString = Regex.Replace(subjectString, #"(.*\bDATE\b\D*).*?(\\.*\bTIME\b\D*).*?(\\.*\bComponentQty\b\D*)\d+(.*)", "$1NEW_DATE$2NEW_TIME$3NEW_QTY", RegexOptions.Singleline);
Where NEW_DATE should be replaced by your date, NEW_TIME by your time, and NEW_QTY by your new qty.
You can create the replacement string from other variables as you please :)
Well well well, .NET and interpolated variables suck.. If you try to change use "$11" in replacement it thinks it has to use backreference #11 and it fails. Also Regexbuddy had a bug which produced the wrong regex. This is tested and works!
string subjectString = "\n\t\"BLOCK\",\"HEADER-\"\r\n\t\t\"NAME\",\"147430\"\r\n\t\t\"REVISION\",\"0000\"\r\n\t\t\"DATE\",\"11/11/10\"\r\n\t\t\"TIME\",\"10:03:47\"\r\n\t\t\"PMABAR\",\"\"\r\n\t\t\"COMMENT\",\"\"\r\n\t\t\"PTPNAME\",\"0805C\"\r\n\t\t\"CMPNAME\",\"0805C\"\r\n\t\"BLOCK\",\"PRTIDDT-\"\r\n\t\t\"PMAPP\",1\r\n\t\t\"PMADC\",0\r\n\t\t\"ComponentQty\",4\r\n\t\"BLOCK\",\"PRTFORM-\"\r\n\t\t....(more)....";
Regex regexObj = new Regex(#"^(.*\bDATE\b\D*).*?(\"".*?\bTIME\b\D*).*?(\"".*?\bComponentQty\b\D*)\d+(.*)$", RegexOptions.Singleline);
StringBuilder myResult = new StringBuilder();
Match matchResults = regexObj.Match(subjectString);
while (matchResults.Success)
{
for (int i = 1; i < matchResults.Groups.Count; i++)
{
Group groupObj = matchResults.Groups[i];
if (groupObj.Success)
{
myResult.Append(groupObj.Value);
switch (i)
{
case 1:
myResult.Append("NEW_DATE");
break;
case 2:
myResult.Append("NEW_TIME");
break;
case 3:
myResult.Append("NEW QTY");
break;
}
}
}
matchResults = matchResults.NextMatch();
}
Console.WriteLine("Final Result : \n\n\n{0}", myResult.ToString());
Output:
Final Result :
"BLOCK","HEADER-"
"NAME","147430"
"REVISION","0000"
"DATE","NEW_DATE"
"TIME","NEW_TIME"
"PMABAR",""
"COMMENT",""
"PTPNAME","0805C"
"CMPNAME","0805C"
"BLOCK","PRTIDDT-"
"PMAPP",1
"PMADC",0
"ComponentQty",NEW QTY
"BLOCK","PRTFORM-"
....(more)....
By the way you have a falsely escaped dot in your input string. Cheers and have fun! :)

If you can change the way your source string looks, I would use String.Format:
string s = String.Format("Date={0}, Name={1}, Quantity={2}", date, name, quantity);
The placeholders {0}, {1}, {2} are replaced with the specified arguments which follow.

To make it cleaner I would create a function to parse that string list, and then another function to create such a string list instead of using regexps. I think this will make your code easier to maintain.
Dictionary<string, string> Parse(List<string> data)
{
...
}
List<string> CreateStringList(Dictionary<string, string> values)
{
...
}
List<string> SetValues(List<string> data)
{
Dictionary<string, string> values = Parse(data);
values["DATE"] = "12/06/11";
values["TIME"] = "10:30:10";
values["ComponentQty"] = "4";
return CreateStringList(values);
}

Related

Remove part of a string between an start and end

Code first:
string myString = "<at>onePossibleName</at> some question here regarding <at>disPossibleName</at>"
// some code to handle myString and save it in myEditedString
Console.WriteLine(myEditedString);
//output now is: some question here regarding <at>disPossibleName</at>
I want to remove <at>onePossibleName</at> from myString. The string onePossibleName and disPossbileName could be any other string.
So far I am working with
string myEditedString = string.Join(" ", myString.Split(' ').Skip(1));
The problem here would be that if onePossibleName becomes one Possible Name.
Same goes for the try with myString.Remove(startIndex, count) - this is not the solution.
There will be different method depending on what you want, you can go with a IndexOf and a SubString, regex would be a solution too.
// SubString and IndexOf method
// Usefull if you don't care of the word in the at tag, and you want to remove the first at tag
if (myString.Contains("</at>"))
{
var myEditedString = myString.Substring(myString.IndexOf("</at>") + 5);
}
// Regex method
var stringToRemove = "onePossibleName";
var rgx = new Regex($"<at>{stringToRemove}</at>");
var myEditedString = rgx.Replace(myString, string.Empty, 1); // The 1 precise that only the first occurrence will be replaced
You could use this generic regular expression.
var myString = "<at>onePossibleName</at> some question here regarding <at>disPossibleName</at>";
var rg = new Regex(#"<at>(.*?)<\/at>");
var result = rg.Replace(myString, "").Trim();
This would remove all 'at' tags and the content between. The Trim() call is to remove any white space at the beginning/end of the string after the replacement.
string myString = "<at>onePossibleName</at> some question here regarding <at>disPossibleName</at>"
int sFrom = myString.IndexOf("<at>") + "<at>".Length;
int sTo = myString.IndexOf("</at>");
string myEditedString = myString.SubString(sFrom, sFrom - sTo);
Console.WriteLine(myEditedString);
//output now is: some question here regarding <at>disPossibleName</at>

How should we reverse format & extract a string in C#?

Pretty sure we all do string.format and define some string in a specifed format.
I have a string which is always formatted in a way like this:
const string myString = string.Format("pt:{0}-first:{1}", inputString);
To get {0}, I can always check for pt:{ and read till }.
But what is the best/recommended way to extract {0} & {1} from the above variable myString ?
A Regex version of answer, but again, assuming your input doesnt contain '-'
var example = = "pt:hello-first:23";
var str = "pt:(?<First>[^-]+)-first:(?<Second>[^%]+)";
var match = new Regex(str).Match(example);
var first = match.Groups["First"].Value;
var second = match.Groups["Second"].Value;
It might be a good idea that you define what your variable can/cannot contain.
Not sure if this is the best way to do it, but it's the most obvious:
string example = "pt:123-first:456";
var split = example.Split('-');
var pt = split[0].Substring(split[0].IndexOf(':') + 1);
var first = split[1].Substring(split[1].IndexOf(':') + 1);
As Shawn said, if you can guarantee that the variables wont contain either : or - this will be adequate.

Need to split something dynamically from a string

I have a string which is somewhat like this:
string data = "I have a {apple} and a {orange}";
I need to extract the content inside {}, let's say for 10 times
I tried this
string[] split = data.Split(new char[] { '{', '}' }, StringSplitOptions.RemoveEmptyEntries);
The problem is my data is going to be dynamic and I wouldn't know at what instance the {<>} would be present, it can also be something like this
Give {Pen} {Pencil}
I guess the above method wouldn't work, so I would really like to know a dynamic way to do this. Any input would be really helpful.
Thanks and Regards
Try this:
string data = "I have a {apple} and a {orange}";
Regex rx = new Regex("{(.*?)}");
foreach (Match item in rx.Matches(data))
{
Console.WriteLine(item.Groups[1].Value);
}
You need to use Regex to get all values you need.
If the string between {} does not contain nested {} you can use a regex to perform this task:
string data = "I have a {apple} and a {orange}";
Regex reg = new Regex(#"\{(?<Name>[A-z0-9]*)\}");
var matches = reg.Matches(data);
foreach (var m in matches.OfType<Match>())
{
Console.WriteLine($"Found {m.Groups["Name"].Value} at {m.Index}");
}
To replace the strings between {} you can use Regex.Replace:
reg.Replace(data, m => m.Groups["Name"].Value + "_")
// Will produce "I have a apple_ and a orange_"
To get the rest of the string, you can use Regex.Split:
Regex reg2 = new Regex(#"\{[A-z0-9]*\}");
var result = reg2.Split(data);
// will contain "I have a ", " and a ", "", you might want to remove ""
As I understand, you want to split that string into parts like this:
I have a
{apple}
and a
{orange}
And then you want to go over those parts and do something with them, and that something is different depending on whether part is enclosed in {} or not. If so - you need Regex.Split:
string data = "I have a {apple} and a {orange}";
var parts = Regex.Split(data, #"({.*?})");
foreach (var part in parts) {
if (part.StartsWith("{") && part.EndsWith("}")) {
var trimmed = part.TrimStart('{').TrimEnd('}');
// "apple" and "orange" go here
// do something with {} part
}
else {
// "I have a " and " and a " go here
// do something with other part
}
}

Extract ID and replace everything in `Example HTML`

New to Regular Expressions, I want to have the following text in my HTML and would like to replace with something else
Example HTML:
{{Object id='foo'}}
Extract the id into a variable like this:
string strId = "foo";
So far I have the following Regular Expression code that will capture the Example HTML:
string strStart = "Object";
string strFind = "{{(" + strStart + ".*?)}}";
Regex regExp = new Regex(strFind, RegexOptions.IgnoreCase);
Match matchRegExp = regExp.Match(html);
while (matchRegExp.Success)
{
//At this point, I have this variable:
//{{Object id='foo'}}
//I can find the id='foo' (see below)
//but not sure how to extract 'foo' and use it
string strFindInner = "id='(.*?)'"; //"{{Slider";
Regex regExpInner = new Regex(strFindInner, RegexOptions.IgnoreCase);
Match matchRegExpInner = regExpInner.Match(matchRegExp.Value.ToString());
//Do something with 'foo'
matchRegExp = matchRegExp.NextMatch();
}
I understand this might be a simple solution, I am hoping to gain more knowledge about Regular Expressions but more importantly, I am hoping to receive a suggestion on how to approach this cleaner and more efficiently.
Thank you
Edit:
Is this an example that I could potentially use: c# regex replace
While I am not solving my initial question with Regular Expressions, I did move into a simpler solution using SubString, IndexOf and string.Split for the time being, I understand that my code needs to be cleaned up but thought I would post the answer that I have thus far.
string html = "<p>Start of Example</p>{{Object id='foo'}}<p>End of example</p>"
string strObject = "Slider"; //Example
//When found, this will contain "{{Object id='foo'}}"
string strCode = "";
//ie: "id='foo'"
string strCodeInner = "";
//Tags will be a list, but in this example, only "id='foo'"
string[] tags = { };
//Looking for the following "{{Object "
string strFindStart = "{{" + strObject + " ";
int intFindStart = html.IndexOf(strFindStart);
//Then ending in the following
string strFindEnd = "}}";
int intFindEnd = html.IndexOf(strFindEnd) + strFindEnd.Length;
//Must find both Start and End conditions
if (intFindStart != -1 && intFindEnd != -1)
{
strCode = html.Substring(intFindStart, intFindEnd - intFindStart);
//Remove Start and End
strCodeInner = strCode.Replace(strFindStart, "").Replace(strFindEnd, "");
//Split by spaces, this needs to be improved if more than IDs are to be used
//but for proof of concept this is perfect
tags = strCodeInner.Split(new char[] { ' ' });
}
Dictionary<string, string> dictTags = new Dictionary<string, string>();
foreach (string tag in tags)
{
string[] tagSplit = tag.Split(new char[] { '=' });
dictTags.Add(tagSplit[0], tagSplit[1].Replace("'", "").Replace("\"", ""));
}
//At this point, I can replace "{{Object id='foo'}}" with anything I'd like
//What I don't show is that I go into the website's database,
//get the object (ie: Slider) and return the html for slider with the ID of foo
html = html.Replace(strCode, strView);
/*
"html" variable may contain:
<p>Start of Example</p>
<p id="foo">This is the replacement text</p>
<p>End of example</p>
*/

How to provide custom string placeholder for string format

I have a string
string str ="Enter {0} patient name";
I am using string.format to format it.
String.Format(str, "Hello");
Now if i want patient also to be retrieved from some config then I need to change str to something like
"Enter {0} {1} name". So it will replace the {1} with second value. The problem is that I want instead of {1} some other format something like {pat}. But when I try to use, it throws an error. The reason I want a different format is that there are lot of files I need to change like this(which may contain {0},{1} etc). So I need a custom placeholder which can be replaced at run-time.
You might want to check out FormatWith 2.0 by James Newton-King. It allows you to use property names as formatting tokens such as this:
var user = new User()
{
Name = "Olle Wobbla",
Age = 25
};
Console.WriteLine("Your name is {Name} and your age is {Age}".FormatWith(user));
You can also use it with anonymous types.
UPDATE: There is also a similar solution by Scott Hanselman but it is implemented as a set of extension methods on Object instead of String.
UPDATE 2012: You can get Calrius Consulting's NETFx String.FormatWith Extension Method NuGet package on NuGet.org
UPDATE 2014: There is also StringFormat.NET and littlebit's StringFormat
Regex with a MatchEvaluator seems a good option:
static readonly Regex re = new Regex(#"\{([^\}]+)\}", RegexOptions.Compiled);
static void Main()
{
string input = "this {foo} is now {bar}.";
StringDictionary fields = new StringDictionary();
fields.Add("foo", "code");
fields.Add("bar", "working");
string output = re.Replace(input, delegate (Match match) {
return fields[match.Groups[1].Value];
});
Console.WriteLine(output); // "this code is now working."
}
object[] myInts = new int[] {8,9};
However you can get away with:
object[] myInts = new string[] { "8", "9" };
string bar = string.Format("{0} {1}", myInts);
I saw all the answers above, yet, couldn't get the question right :)
Is there any particular reason why the following code does not meet your requirement?
string myFirstStr = GetMyFirstStrFromSomewhere();
string mySecondStr = GetMySecondStrFromSomewhere();
string result = "Enter " + myFirstStr + " " + mySecondStr + " name";
Here's another version of this that I found here: http://www.reddit.com/r/programming/comments/bodml/beef_up_params_in_c_5_to_solve_lambda_abuse/c0nrsf1
Any solution to this is going to involve reflection, which is less than ideal, but here's his code with some of the other major performance issues resolved. (No error checking. Add it if you like.):
1) Uses direct runtime reflection, no DataBinder overhead
2) Doesn't use regular expressions, uses a single-pass parse and state.
3) Doesn't convert the string into an intermediate string and then convert it again to the final format.
4) Allocates and concatenates with a single StringBuilder instead of newing up strings all over the place and concatenating them into new strings.
5) Removes the stack overhead of calling a delegate for n replace operations.
6) In general is a single pass through that will scale in a relatively linear manner (still some cost for each prop lookup and nested prop lookup, but that's that.)
public static string FormatWith(this string format, object source)
{
StringBuilder sbResult = new StringBuilder(format.Length);
StringBuilder sbCurrentTerm = new StringBuilder();
char[] formatChars = format.ToCharArray();
bool inTerm = false;
object currentPropValue = source;
for (int i = 0; i < format.Length; i++)
{
if (formatChars[i] == '{')
inTerm = true;
else if (formatChars[i] == '}')
{
PropertyInfo pi = currentPropValue.GetType().GetProperty(sbCurrentTerm.ToString());
sbResult.Append((string)(pi.PropertyType.GetMethod("ToString", new Type[]{}).Invoke(pi.GetValue(currentPropValue, null), null)));
sbCurrentTerm.Clear();
inTerm = false;
currentPropValue = source;
}
else if (inTerm)
{
if (formatChars[i] == '.')
{
PropertyInfo pi = currentPropValue.GetType().GetProperty(sbCurrentTerm.ToString());
currentPropValue = pi.GetValue(source, null);
sbCurrentTerm.Clear();
}
else
sbCurrentTerm.Append(formatChars[i]);
}
else
sbResult.Append(formatChars[i]);
}
return sbResult.ToString();
}
You can also use the example from Marc Gravell and Extend the String class object:
public static class StringExtension
{
static readonly Regex re = new Regex(#"\{([^\}]+)\}", RegexOptions.Compiled);
public static string FormatPlaceholder(this string str, Dictionary<string, string> fields)
{
if (fields == null)
return str;
return re.Replace(str, delegate(Match match)
{
return fields[match.Groups[1].Value];
});
}
}
Example usage:
String str = "I bought a {color} car";
Dictionary<string, string> fields = new Dictionary<string, string>();
fields.Add("color", "blue");
str.FormatPlaceholder(fields));
You are probably better off using Replace for the custom field and Format for the rest, like:
string str = "Enter {0} {pat} name";
String.Format(str.Replace("{pat}", "Patient"), "Hello");
var user = new User()
{
Name = "John",
Age = 21
};
String result = $"Your name is {user.Name} and your age is {user.Age}";
I wanted something that worked more like Python's string formatting, so I wrote this:
https://gist.github.com/samwyse/b225b32ae1aea6fb27ad9c966b9ca90b
Use it like this:
Dim template = New FormatFromDictionary("{cat} vs {dog}")
Dim d = New Dictionary(Of String, Object) From {
{"cat", "Felix"}, {"dog", "Rex"}}
Console.WriteLine(template.Replace(d)) ' Felix vs Rex

Categories