Find and replace dynamic values via for loop - c#

http://www.test.com/test.aspx?testinfo=&|&
I am trying to replace & with values from a table. I got name and age as two paramaters that I need to substitue and get url like this:
http://www.test.com/test.aspx?testinfo=name|age
If I have 3 string parameters to be replaced for a url:
http://www.test.com/test.aspx?testinfo=&|&
Viz name, age, address for the above url:
http://www.test.com/test.aspx?testinfo=name|age|address
string URL=string.Empty;
URL=http://www.test.com/test.aspx?testinfo=&|&;
//in this case fieldsCount is 2, ie. name and age
for(int i=0; i<fieldsCount.Length-1;i++)
{
URL.Replace("*","name");
}
How do I add "age" so that I get ? any inputs will be helpful.
http://www.test.com/test.aspx?testinfo=name|age

I think this is what you want,
List<string> keys = new List<string>() { "name", "age", "param3" };
string url = "http://www.test.com/test.aspx?testinfo=&|&;";
Regex reg = new Regex("&");
int count = url.Count(p => p == '&');
for (int i = 0; i < count; i++)
{
if (i >= keys.Count)
break;
url = reg.Replace(url, keys[i], 1);
}

I'm curious about two things.
Why are you using & as something to replace, when this has contextual
meaning within the query string as a delimiter between key/value
pairs?
Why does your string have just 2 fields (&|&), when sometimes
the value to replace it with has more than 2 keys?
If these things don't matter, it would make more sense to me to have a replacement string of something else... for instance http://www.test.com/test.aspx?testinfo=[testinfo]. Of course, you need to choose something that has 0 chance of showing up in your Url apart from where you expect it. You can then replace it with something like the following:
url = url.Replace("[testinfo]", string.Join("|", fieldsCount));
Note that this doesn't require your for-loop, and should result in your expected url.
See string.Join on msdn.
Concatenates all the elements of a string array, using the specified
separator between each element.

If I understood right, I think you need something like this:
private static string SubstituteAmpersands(string url, string[] substitutes)
{
StringBuilder result = new StringBuilder();
int substitutesIndex = 0;
foreach (char c in url)
{
if (c == '&' && substitutesIndex < substitutes.Length)
result.Append(substitutes[substitutesIndex++]);
else
result.Append(c);
}
return result.ToString();
}

Related

How to implement "Find, Replace, Next" in a String on C#?

I'm searching for a solution to this case:
I have a Method inside a DLL that receive a string that contains some words as "placeholders/parameters" that will be replaced by a result of another specific method (inside dll too)
Too simplificate: It's a query string received as an argument to be on a method inside a DLL, where X word that matchs a specifc case, will be replaced.
My method receive a string that could be like this:
(on .exe app)
string str = "INSERT INTO mydb.mytable (id_field, description, complex_number) VALUES ('#GEN_COMPLEX_ID#','A complex solution', '#GEN_COMPLEX_ID#');"
MyDLLClass.MyMethod(str);
So, the problem is: if i replace the #GEN_COMPLEX_ID# on this string, wanting that a different should be on each match, it not will happen because the replaced executes the function in a single shot (not step by step). So, i wanna help to implement this: a step by step replace of any text (like Find some word, replace, than next ... replace ... next... etc.
Could you help me?
Thanks!
This works pretty well for me:
string yourOriginalString = "ab cd ab cd ab cd";
string pattern = "ab";
string yourNewDescription = "123";
int startingPositionOffset = 0;
int yourOriginalStringLength = yourOriginalString.Length;
MatchCollection match = Regex.Matches(yourOriginalString, pattern, RegexOptions.IgnoreCase | RegexOptions.Multiline);
foreach (Match m in match)
{
yourOriginalString = yourOriginalString.Substring(0, m.Index+startingPositionOffset) + yourNewDescription + yourOriginalString.Substring(m.Index + startingPositionOffset+ m.Length);
startingPositionOffset = yourOriginalString.Length - yourOriginalStringLength;
}
If what you're asking is how to replace each placeholder with a different value, you can do it using the Regex.Replace overload which accepts a MatchEvaluator delegate, and executes it for each match:
// conceptually, something like this (note that it's not checking if there are
// enough values in the replacementValues array)
static string ReplaceMultiple(
string input, string placeholder, IEnumerable<string> replacementValues)
{
var enumerator = replacementValues.GetEnumerator();
return Regex.Replace(input, placeholder,
m => { enumerator.MoveNext(); return enumerator.Current; });
}
This is, of course, presuming that all placeholders look the same.
Pseudo-code
var split = source.Split(placeholder); // create array of items without placeholders
var result = split[0]; // copy first item
for(int i = 1; i < result.Length; i++)
{
bool replace = ... // ask user
result += replace ? replacement : placeholder; // to put replacement or not to put
result += split[i]; // copy next item
}
you should use the split method like this
string [] placeholder = {"#Placeholder#"} ;
string[] request = cd.Split(placeholder, StringSplitOptions.RemoveEmptyEntries);
StringBuilder requetBuilding = new StringBuilder();
requetBuilding.Append(request[0]);
int index = 1;
requetBuilding.Append("Your place holder replacement");
requetBuilding.Append(request[index]);
index++; //next replacement
// requetBuilding.Append("Your next place holder replacement");
// requetBuilding.Append(request[index]);

Remove certain letters from input string

I'm currently having a problem where when I search for a code I want to remove the any "."'s a user has inputted. The code I've done doesn't seem to be working and was wondering if someone could tell me why and what I need to do. Thanks.
foreach (var letters in id)
{
string letter = letters.ToString();
if (letter == ".")
{
id.Replace(letter, "");
}
}
String in .NET is an immutable type, therefore you can't change the value of an existing string variable, you need to replace it entirely with the value returned by Replace i.e.
id = id.Replace(letter, "");
FYI you don't have to check whether . is contained in the string, you can just call Replace(".", "") on the resultant string and it will remove any . present i.e.
id = id.Replace(".", "");
See example
String replace method
id = id.Replace(",", "");
Programmaticaly, maybe you can use that besides Replace() method
string m_tempStr = "This.is.a.test";
List<string> myList = new List<string>();
for (int i = 0; i < m_tempStr.Length; i++)
{
if (m_tempStr[i].ToString() != ".")
{
myList.Add(m_tempStr[i].ToString());
}
}
And than, you can get each member of list like following sample code
foreach (var item in myList)
{
Console.Write(item);
}

Unable to Split the string accordingly

I know this question would have been asked infinite number of times, but I'm kinda stuck.
I have a string something like
"Doc1;Doc2;Doc3;12"
it can be something like
"Doc1;Doc2;Doc3;Doc4;Doc5;56"
Its like few pieces of strings separated by semicolon, followed by a number or id.
I need to extract the number/id and the strings separately.
To be exact, I can have 2 strings: one having "Doc1;Doc2;Doc3" or "Doc1;Doc2;Doc3;Doc4" and the other having just the number/id as "12" or "34" or "45" etc.
And yeah I am using C# 3.5
I understand its a pretty easy and witty question, but this guy is stuck.
Assistance required from experts.
Regards
Anurag
string.LastIndexOf and string.Substring are the keys to what you're trying to do.
var str = "Doc1;Doc2;Doc3;12";
var ind = str.LastIndexOf(';');
var str1 = str.Substring(0, ind);
var str2 = str.Substring(ind+1);
One way:
string[] tokens = str.Split(';');
var docs = tokens.Where(s => s.StartsWith("Doc", StringComparison.OrdinalIgnoreCase));
var numbers = tokens.Where(s => s.All(Char.IsDigit));
String docs = s.Substring(0, s.LastIndexOf(';'));
String number = s.Substring(s.LastIndexOf(';') + 1);
One possible approach would be this:
var ids = new List<string>();
var nums = new List<string>();
foreach (var s in input.Split(';'))
{
int val;
if (!int.TryParse(s, out val)) { ids.Add(s); }
else { nums.Add(s); }
}
where input is something like Doc1;Doc2;Doc3;Doc4;Doc5;56. Now, ids will house all of the Doc1 like values and nums will house all of the 56 like values.
you can use StringTokenizer functionality.
http://www.c-sharpcorner.com/UploadFile/pseabury/JavaLikeStringTokenizer11232005015829AM/JavaLikeStringTokenizer.aspx
split string using ";"
StringTokenizer st = new StringTokenizer(src1,";");
collect final String. that will be your ID.
You may try one of two options: (assuming your input string is in string str;
Approach 1
Get LastIndexOf(';')
Split the string based on the index. This will give you string and int part.
Split the string part and process it
Process the int part
Approach 2
Split the string on ;
Run a for loop - for (int i = 0; i < str.length - 2; i++) - this is the string part
Process str[length - 1] separately - this is the int part
Please take this as a starting point as there could be other approaches to implement a solution for this
string actual = "Doc1;Doc2;Doc3;12";
int lstindex = actual.LastIndexOf(';');
string strvalue = actual.Substring(0, lstindex);
string id = actual.Substring(lstindex + 1);

Get the different substrings from one main string

I have the following main string which contains link Name and link URL. The name and url is combined with #;. I want to get the string of each link (name and url i.e. My web#?http://www.google.com), see example below
string teststring = "My web#;http://www.google.com My Web2#;http://www.bing.se Handbooks#;http://www.books.se/";
and I want to get three different strings using any string function:
My web#?http://www.google.com
My Web2#?http://www.bing.se
Handbooks#?http://www.books.de
So this looks like you want to split on the space after a #;, instead of splitting at #; itself. C# provides arbitrary length lookbehinds, which makes that quite easy. In fact, you should probably do the replacement of #; with #? first:
string teststring = "My web#;http://www.google.com My Web2#;http://www.bing.se Handbooks#;http://www.books.se/";
teststring = Regex.Replace(teststring, #"#;", "#?");
string[] substrings = Regex.Split(teststring, #"(?<=#\?\S*)\s+");
That's it:
foreach(var s in substrings)
Console.WriteLine(s);
Output:
My web#?http://www.google.com
My Web2#?http://www.bing.se
Handbooks#?http://www.books.se/
If you are worried that your input might already contain other #? that you don't want to split on, you can of course do the splitting first (using #; in the pattern) and then loop over substrings and do the replacement call inside the loop.
If these are constant strings, you can just use String.Substring. This will require you to count letters, which is a nuisance, in order to provide the right parameters, but it will work.
string string1 = teststring.Substring(0, 26).Replace(";","?");
If they aren't, things get complicated. You could almost do a split with " " as the delimiter, except that your site name has a space. Do any of the substrings in your data have constant features, such as domain endings (i.e. first .com, then .de, etc.) or something like that?
If you have any control on the input format, you may want to change it to be easy to parse, for example by using another separator between items, other than space.
If this format can't be changed, why not just implement the split in code? It's not as short as using a RegEx, but it might be actually easier for a reader to understand since the logic is straight forward.
This will almost definitely will be faster and cheaper in terms of memory usage.
An example for code that solves this would be:
static void Main(string[] args)
{
var testString = "My web#;http://www.google.com My Web2#;http://www.bing.se Handbooks#;http://www.books.se/";
foreach(var x in SplitAndFormatUrls(testString))
{
Console.WriteLine(x);
}
}
private static IEnumerable<string> SplitAndFormatUrls(string input)
{
var length = input.Length;
var last = 0;
var seenSeparator = false;
var previousChar = ' ';
for (var index = 0; index < length; index++)
{
var currentChar = input[index];
if ((currentChar == ' ' || index == length - 1) && seenSeparator)
{
var currentUrl = input.Substring(last, index - last);
yield return currentUrl.Replace("#;", "#?");
last = index + 1;
seenSeparator = false;
previousChar = ' ';
continue;
}
if (currentChar == ';' && previousChar == '#')
{
seenSeparator = true;
}
previousChar = currentChar;
}
}

C# Template parsing and matching with text file

Need some ideas how to solve this problem.
I have a template file what describes the line in the text file. For example:
Template
[%f1%]|[%f2%]|[%f3%]"[%f4%]"[%f5%]"[%f6%]
Text file
1234|1234567|123"12345"12"123456
Now i need to read in the fields from the text file. In the template file fields are described with [%some name%]. Allso in the template file there is set what the field separators are, in this example here there are | and ". The lenght of the fields can change through different files but the separators will stay the same. What would be the best way to read in the template and by template read in the text file?
EDIT: Text file has multiple rows, like this:
1234|1234567|123"12345"12"123456"\r\n
1234|field|123"12345"12"asdasd"\r\n
123sd|1234567|123"asdsadf"12"123456"\r\n
45gg|somedata|123"12345"12"somefield"\r\n
EDIT2: Ok, lets make it even harder. Some fields can contain binary data and i know the starting and end position of the binary data field. I should be able to mark those fields in the template and then the parser will know that this field is binary. How to solve this problem?
I would create a regex based on the template and then parse the text file using that:
class Parser
{
private static readonly Regex TemplateRegex =
new Regex(#"\[%(?<field>[^]]+)%\](?<delim>[^[]+)?");
readonly List<string> m_fields = new List<string>();
private readonly Regex m_textRegex;
public Parser(string template)
{
var textRegexString = '^' + TemplateRegex.Replace(template, Evaluator) + '$';
m_textRegex = new Regex(textRegexString);
}
string Evaluator(Match match)
{
// add field name to collection and create regex for the field
var fieldName = match.Groups["field"].Value;
m_fields.Add(fieldName);
string result = "(.*?)";
// add delimiter to the regex, if it exists
// TODO: check, that only last field doesn't have delimiter
var delimGroup = match.Groups["delim"];
if (delimGroup.Success)
{
string delim = delimGroup.Value;
result += Regex.Escape(delim);
}
return result;
}
public IDictionary<string, string> Parse(string text)
{
var match = m_textRegex.Match(text);
var groups = match.Groups;
var result = new Dictionary<string, string>(m_fields.Count);
for (int i = 0; i < m_fields.Count; i++)
result.Add(m_fields[i], groups[i + 1].Value);
return result;
}
}
You can parse the template using regular expressions. An expression like this will match each field definition and separator:
Match m = Regex.Match(template, #"^(\[%(?<name>.+?)%\](?<separator>.)?)+$")
The match will contain two named groups for (name and separator), each of which will contain a number of captures for each time they matched in the input string. In your example, the separator group would have one less capture than the name group.
You can then iterate over the captures, and use the results to extract the fields from the input string and store the values, like this:
if( m.Success )
{
Group name = m.Groups["name"];
Group separator = m.Groups["separator"];
int index = 0;
Dictionary<string, string> fields = new Dictionary<string, string>();
for( int x = 0; x < name.Captures.Count; ++x )
{
int separatorIndex = input.Length;
if( x < separator.Captures.Count )
separatorIndex = input.IndexOf(separator.Captures[x].Value, index);
fields.Add(name.Captures[x].Value, input.Substring(index, separatorIndex - index));
index = separatorIndex + 1;
}
// Do something with results.
}
Obviously in a real program you'd have to account for invalid input and such, which I didn't do here.
I would do this with a few lines of code. Loop through your template row, grabbing all text between "[" as the variable name and everything else as a terminator. Read all the text to the terminal, assign it to the variable name, repeat.
1- Use API for that sscanf(line, format, __arglist) check here
2- Use string split Like:
public IEnumerable<int> GetDataFromLines(string[] lines)
{
//handle the output data
List<int> data = new List<int>();
foreach (string line in lines)
{
string[] seperators = new string[] { "|", "\"" };
string[] results = line.Split(seperators, StringSplitOptions.RemoveEmptyEntries);
foreach (string result in results)
{
data.Add(int.Parse(result));
}
}
return data;
}
Test it with line:
line = "1234|1234567|123\"12345\"12\"123456";
string[] lines = new string[] { line };
GetDataFromLines(lines);
//output list items are:
1234
1234567
123
12345
12
123456

Categories

Resources