I have a name which is made of a prefix a type and name , i want to retrieve the name part.
Prefix always remains same but Type can change.
I have the following code to get the name part:
string prefix = "Prefix-";
string str =prefix + "Type-hello-j---.xml";
str = Path.GetFileNameWithoutExtension(str);
str = str.Substring(prefix.Length);
str = str.Substring(str.IndexOf('-') + 1);
In the above example the name part is: hello-j---
Is there any efficient/better way to do the same in C# ?
You can use an overload of string.Split() that lets you specify the number of parts:
string fileName = "Prefix-Type-hello-j---.xml";
string withoutExtension = Path.GetFileNameWithoutExtension(str);
var parts = str.Split(new[]{'-'}, 3);
string name = parts[2];
If this is always the structure of your string, this would work :
string name = str.Split(new[]{'-'})[2];
I'm assuming you only want "hello". If you want the rest of the name you could use the overloaded method as #KingCronus suggested :
string name = str.Split(new[]{'-'}, 3)[2];
You can also create an extension function that works like String.IndexOf but that gets the position of the nth occurrence of the specified character:
public static int IndexOfWithCount(this string input, char character, int occurenceNumber)
{
int count = 0;
for (int numCaracter = 0; numCaracter < input.Length; numCaracter++)
if (input[numCaracter] == character)
{
count++;
if (count == occurenceNumber)
return numCaracter;
}
return -1;
}
To use it:
string nameWithoutExt = Path.GetFileNameWithoutExtension(str);
string result = nameWithoutExt.Substring(nameWithoutExt.IndexOfWithCount('-', 2) + 1);
It depends how you define efficient but if lines of code fits your defintion how about:
var str = "prefix-Type-hello-j---.xml";
var name = Regex.Match(str, #"(.+?-)(.+?-)(?<name>.+)\.").Groups["name"].Value;
The first two capturing groups consume the prefix and the the type then the namedgroup consumes the name until the extension starts.
This code assumes there is always a match, if there is not it will throw a nullreference exception.
See Regex.Match
Related
I have a string that contains a first and last name and I wanted to split into two separate strings so I used this code:
string Delname = bkDel.ContactName;
string[] Deltmp = Delname.Split(' ');
string DelFirstName = Deltmp[0];
string DelLastName = Deltmp[1];
It works fine if there is a first and last name but this causes an error if the name string only contains a first name:
Index was outside the bounds of the array.
since Deltmp[1] is null.
Is there a way to check the name string so if it only contains one string then don't try and split?
You can either check on the length of the array:
if (Deltmp.Length > 1)
//Assign to vars
Or you can check if the input string contains spaces:
if (Delname.Contains(" "))
//Do split
For example:
string[] Deltmp = Delname.Split(' ');
if (Deltmp.Length > 1)
//Assign to both
else
//Assign to only one
You could do a simple check like this.
if(Delname.Split(' ').Count() > 1)
{
// Has First and Last Name
}
else
{
// Has Single Name
}
You can use Delname.Trim(' ') method to delete spaces from start and end, and then check string with Delname.Contains(" "))
What about checking the input with regular expressions? Here is a simple regex pattern, but you may need to get more sophisticated depending on your supported language requirements.
Regex reg = new Regex(#"[A-Za-z]+ [A-Za-z]+");
string Delname = bkDel.ContactName;
Delname = Delname.Trim()
if (!reg.IsMatch(Delname)){
// Don't split
return;
}
string[] Deltmp = Delname.Split(' ');
string DelFirstName = Deltmp[0];
string DelLastName = Deltmp[1];
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]);
string containsCharacter = textBox1.Text;
string testString = "test string contains certain characters";
int count = testString.Split(containsCharacter).Length - 1;
I originally pulled this code off another person's question's answer but it doesn't seem to work with text boxes.
Errors I'm getting:
The best overloaded method match for 'string.Split(params char[])' has some invalid arguments
Argument 1: cannot convert from 'string' to 'char[]'
I prefer to fix this code rather than use other things like LINQ but I would accept it if there isn't a way to fix this code.
You could iterate through the characters
string value = "BANANA";
int x = 0;
foreach (char c in value)
{
if (c == 'A')
x++;
}
string containsCharacter = "t";
string testString = "test string contains certain characters";
int count = testString.Count(x => x.ToString() == containsCharacter);
This example will return 6.
The Split version you are using expects a character as input. This is the version for strings:
string containsText = textBox1.Text;
string testString = "test string contains certain characters";
int count = testString.Split(new string[]{containsText}, StringSplitOptions.None).Length - 1;
With this code, count will be: 1 if textBox1.Text includes "test", 6 if it contains "t", etc. That is, it can deal with any string (whose length might be one, as a single character, or as big as required).
You can call ToCharArray on the string to make it a char[], like this:
int count = testString.Split(containsCharacter.ToCharArray()).Length - 1;
Since Split takes characters as a param, you could rewrite this by listing the characters being counted directly, as follows:
int count = testString.Split(',', ';', '-').Length - 1;
"this string. contains. 3. dots".Split(new[] {"."}, StringSplitOptions.None).Count() - 1
Edit:
Upon Reading your code more carefully I suggest you do this, you should rephrase your question to
"Check the number of occurences of a certain string in Another string":
string containsString = "this";
string test = "thisisateststringthisisateststring";
var matches = Regex.Matches(test,containsString).Count;
matches is 2!
My initial post answers your actual question "occurrences of a certain character in a string":
string test = "thisisateststring";
int count = test.Count(w => w == 'i');
Count is 3!
In my code behind in C# I have the following code. How do I change the replace so that only
the first occurance of www is replaced?
For example if the User enters www.testwww.com then I should be saving it as testwww.com.
Currently as per the below code it saves as www.com (guess due to substr code).
Please help. Thanks in advance.
private string FilterUrl(string url)
{
string lowerCaseUrl = url.ToLower();
lowerCaseUrl = lowerCaseUrl.Replace("http://", string.Empty).Replace("https://", string.Empty).Replace("ftp://", string.Empty);
lowerCaseUrl = lowerCaseUrl.Replace("www.", string.Empty);
string lCaseUrl = url.Substring(url.Length - lowerCaseUrl.Length, lowerCaseUrl.Length);
return lCaseUrl;
}
As Ally suggested. You are much better off using System.Uri. This also replaces the leading www as you wish.
private string FilterUrl(string url)
{
Uri uri = new UriBuilder(url).Uri; // defaults to http:// if missing
return Regex.Replace(uri.Host, "^www.", "") + uri.PathAndQuery;
}
Edit: The trailing slash is because of the PathAndQuery property. If there was no path you are left with the slash only. Just add another regex replace or string replace. Here's the regex way.
return Regex.Replace(uri.Host, "^www.", "") + Regex.Replace(uri.PathAndQuery, "/$", "");
I would suggest using indexOf(string) to find the first occurrence.
Edit: okay someone beat me to it ;)
You could use IndexOf like Felipe suggested OR do it the low tech way..
lowerCaseUrl = lowerCaseUrl.Replace("http://", string.Empty).Replace("https://", string.Empty).Replace("ftp://", string.Empty).Replace("http://www.", string.Empty).Replace("https://www.", string.Empty)
Would be interested to know what you're trying to achieve.
Came up with a cool static method, also works for replacing the first x occurrences:
public static string ReplaceOnce(this string s, string replace, string with)
{
return s.ReplaceCount(replace, with);
}
public static string ReplaceCount(this string s, string replace, string with, int howManytimes = 1)
{
if (howManytimes < 0) throw InvalidOperationException("can not replace a string less than zero times");
int count = 0;
while (s.Contains(replace) && count < howManytimes)
{
int position = s.IndexOf(replace);
s = s.Remove(position, replace.Length);
s = s.Insert(position, with);
count++;
}
return s;
}
The ReplaceOnce isn't necessary, just a simplifier. Call it like this:
string url = "http://www.stackoverflow.com/questions/www/www";
var urlR1 - url.ReplaceOnce("www", "xxx");
// urlR1 = "http://xxx.stackoverflow.com/questions/www/www";
var urlR2 - url.ReplaceCount("www", "xxx", 2);
// urlR2 = "http://xxx.stackoverflow.com/questions/xxx/www";
NOTE: this is case-sensitive as it is written
The Replace method will change all content of the string. You have to locate the piece you want to remove using IndexOf method, and remove using Remove method of string. Try something like this:
//include the namespace
using System.Globalization;
private string FilterUrl(string url)
{
// ccreate a Comparer object.
CompareInfo myCompare = CultureInfo.InvariantCulture.CompareInfo;
// find the 'www.' on the url parameter ignoring the case.
int position = myCompare.IndexOf(url, "www.", CompareOptions.IgnoreCase);
// check if exists 'www.' on the string.
if (position > -1)
{
if (position > 0)
url = url.Remove(position - 1, 5);
else
url = url.Remove(position, 5);
}
//if you want to remove http://, https://, ftp://.. keep this line
url = url.Replace("http://", string.Empty).Replace("https://", string.Empty).Replace("ftp://", string.Empty);
return url;
}
Edits
There was a part in your code that is removing a piece of string. If you just want to remove the 'www.' and 'http://', 'https://', 'ftp://', take a look the this code.
This code also ignore the case when it compares the url parameter and what you have been findind, on case, 'www.'.
i have a string:
e.g. WORD1_WORD2_WORD3
how do i get just WORD1 from the string?
i.e the text before the first underscore
It may be tempting to say Split - but that involves the creating of an array and lots of individual strings. IMO, the optimal way here is to find the first underscore, and take a substring:
string b = s.Substring(0, s.IndexOf('_')); // assumes at least one _
(edit)
If you are doing this lots, you could add some extension methods:
public static string SubstringBefore(this string s, char value) {
if(string.IsNullOrEmpty(s)) return s;
int i = s.IndexOf(value);
return i > 0 ? s.Substring(0,i) : s;
}
public static string SubstringAfter(this string s, char value) {
if (string.IsNullOrEmpty(s)) return s;
int i = s.IndexOf(value);
return i >= 0 ? s.Substring(i + 1) : s;
}
then:
string s = "a_b_c";
string b = s.SubstringBefore('_'), c = s.SubstringAfter('_');
YOUR_STRING.Split('_')[0]
In fact the Split method returns an array of strings resulting from splitting the original string at any occurrence of the specified character(s), not including the character at which the split was performed.
if s is the string:
int idx = s.IndexOf('_');
if (idx >= 0)
firstPart = s.Substring(0,idx);
("WORD1_WORD2_WORD3").Split('_')[0]
should return "WORD1". If it doesn't work try .Spilt() on a string variable with the Content you specified.
string str="WORD1_WORD2_WORD3";
string result=str.Split('_')[0];
This actually returns an array:
{"WORD1", "WORD2", "WORD3"}
There are several ways. You can use Split, Substring. etc. An example with Split:
String var = "WORD1_WORD2_WORD3";
String result = var.Split('_')[0];