I would like to remove the last segment of Request.Url, so for instance...
http://www.example.com/admin/users.aspx/deleteUser
would change to
http://www.example.com/admin/users.aspx
I would prefer linq but accept any solution that efficiently works.
Use the Uri class to parse the URI - you can access all the segments using the Segments property and rebuild the URI without the last segment.
var uri = new Uri(myString);
var noLastSegment = string.Format("{0}://{1}", uri.Scheme, uri.Authority);
for(int i = 0; i < uri.Segments.Length - 1; i++)
{
noLastSegment += uri.Segments[i];
}
noLastSegment = noLastSegment.Trim("/".ToCharArray()); // remove trailing `/`
As an alternative to getting the scheme and host name, as suggested by Dour High Arch in his comment:
var noLastSegment = uri.GetComponents(UriComponents.SchemeAndServer,
UriFormat.SafeUnescaped);
Much the same as #Oded's answer, but using a UriBuilder instead:
var uri = new Uri("http://www.example.com/admin/users.aspx/deleteUser");
var newSegments = uri.Segments.Take(uri.Segments.Length - 1).ToArray();
newSegments[newSegments.Length-1] =
newSegments[newSegments.Length-1].TrimEnd('/');
var ub=new UriBuilder(uri);
ub.Path=string.Concat(newSegments);
//ub.Query=string.Empty; //maybe?
var newUri=ub.Uri;
To remove the last segment of Request.Url it is enough to subtract from absolute uri the length of last segment.
string uriWithoutLastSegment = Request.Url.AbsoluteUri.Remove(
Request.Url.AbsoluteUri.Length - Request.Url.Segments.Last().Length );
I find manipulating Uri's fairly annoying, and as the other answers are quite verbose, here's my two cents in the form of an extension method.
As a bonus you also get a replace last segement method. Both methods will leave querystring and other parts of the url intact.
public static class UriExtensions
{
private static readonly Regex LastSegmentPattern =
new Regex(#"([^:]+://[^?]+)(/[^/?#]+)(.*$)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static Uri ReplaceLastSegement(this Uri me, string replacement)
=> me != null ? new Uri(LastSegmentPattern.Replace(me.AbsoluteUri, $"$1/{replacement}$3")) : null;
public static Uri RemoveLastSegement(this Uri me)
=> me != null ? new Uri(LastSegmentPattern.Replace(me.AbsoluteUri, "$1$3")) : null;
}
Well the trivial solution would be to iterate char by char from the end of the string towards its beginning and search for the first '/' to come (I guess that also came into your mind).
Try this:
string url = "http://www.example.com/admin/users.aspx/deleteUser";
for (int i = url.Length - 1; i >= 0; i--) {
if (url[i] == '/') return url.Substring(0, i - 1);
}
Related
I need to extract the rest of the portion of the URL after "home"
for example the URLs can be
https://www.example.com/site/country/home/products
https://www.example.com/site/country/home/products/consumer
https://www.example.com/site/country/home/products/consumer/kids
The keywords in the url "site", "country" might change.
All I need in the output is:
/products
/products/consumer
/products/consumer/kids
I tried using Regex, but didn't worked in above situation
As suggested by Corion and David in the comments, in this case, the simplest method is probably just to find the index of /home/ and then strip everything up to that point (but not second /):
string home = "/home/";
int homeIndex = url.IndexOf(home);
string relativeUrl = url.Substring(homeIndex + home.Length - 1);
Using a regular expression, you want to match the /home/ substring, and capture the second / and everything following it:
Match match = Regex.Match(url, #"/home(/.*)");
string relativeUrl = "/";
if (match.Success) {
relativeUrl = match.Groups[1].Value;
}
its a so simple c# code i think it may help you
string sub = "https://www.example.com/site/country/home/products";
string temp = "";
string[] ss = sub.Split('/');
for(int i = 0; i < sub.Length; i++)
{
if (ss[i] == "home")
{
i++;
for (int j = i; j < ss.Length; j++)
temp +='/'+ ss[j];
break;
}
}
Console.WriteLine(temp);
You could use the System.Uri class to extract the segments of the URL:
Uri link = new Uri("https://www.example.com/site/country/home/products/consumer/kids");
string[] segs = link.Segments;
int idxOfHome = Array.IndexOf(segs, "home/");
string restOfUrl = string.Join("", segs, idxOfHome+1, segs.Length - (idxOfHome + 1));
Yeilds:
products/consumer/kids
It is easy using Regex. Please use the following Regex and test your scenario. It works fine.
Regex: '(?<=\/home).*\b'
No need to worry about front portion before home. As soon as it finds home, it will take words after home.
hi i was trying to make a program that modified a word in a string to a uppercase word.
the uppercase word is in a tag like this :
the <upcase>weather</upcase> is very <upcase>hot</upcase>
the result :
the WEATHER is very HOT
my code is like this :
string upKey = "<upcase>";
string lowKey = "</upcase>";
string quote = "the lazy <upcase>fox jump over</upcase> the dog <upcase> something here </upcase>";
int index = quote.IndexOf(upKey);
int indexEnd = quote.IndexOf(lowKey);
while(index!=-1)
{
for (int a = 0; a < index; a++)
{
Console.Write(quote[a]);
}
string upperQuote = "";
for (int b = index + 8; b < indexEnd; b++)
{
upperQuote += quote[b];
}
upperQuote = upperQuote.ToUpper().ToString();
Console.Write(upperQuote);
for (int c = indexEnd+9;c<quote.Length;c++)
{
if (quote[c]=='<')
{
break;
}
Console.Write(quote[c]);
}
index = quote.IndexOf(upKey, index + 1);
indexEnd = quote.IndexOf(lowKey, index + 1);
}
Console.WriteLine();
}
i have been trying using this code,and a while(while (indexEnd != -1)) :
index = quote.IndexOf(upKey, index + 1);
indexEnd = quote.IndexOf(lowKey, index + 1);
but that not work, the program run into unlimited loop, btw i'm a noob so please give a answer that i can understand :)
You can use a regular expression for this:
string input = "the <upcase>weather</upcase> is very <upcase>hot</upcase>";
var regex = new Regex("<upcase>(?<theMatch>.*?)</upcase>");
var result = regex.Replace(input, match => match.Groups["theMatch"].Value.ToUpper());
// result will be: "the WEATHER is very HOT"
Here's an explanation taken from here for the regular expression used above:
<upcase> matches the characters <upcase> literally (case sensitive)
(?<theMatch>.\*?) Named capturing group theMatch
.*? matches any character (except newline)
Quantifier: *? Between zero and unlimited times, as few times as possible, expanding as needed [lazy]
< matches the characters < literally
/ matches the character / literally
upcase> matches the characters upcase> literally (case sensitive)
The following will work as long as there are only matching tags and none of them are nested.
public static string Upper(string str)
{
const string start = "<upcase>";
const string end = "</upcase>";
var builder = new StringBuilder();
// Find the first start tag
int startIndex = str.IndexOf(start);
// If no start tag found then return the original
if (startIndex == -1)
return str;
// Append the part before the first tag as is
builder.Append(str.Substring(0, startIndex));
// Continue as long as we find another start tag.
while (startIndex != -1)
{
// Find the end tag for the current start tag
var endIndex = str.IndexOf(end, startIndex);
// Append the text between the start and end as upper case.
builder.Append(
str.Substring(
startIndex + start.Length,
endIndex - startIndex - start.Length).ToUpper());
// Find the next start tag.
startIndex = str.IndexOf(start, endIndex);
// Append the part after the end tag, but before the next start as is
builder.Append(
str.Substring(
endIndex + end.Length,
(startIndex == -1 ? str.Length : startIndex) - endIndex - end.Length));
}
return builder.ToString();
}
I'm not rewriting your code. Just answering your (main) question:
You need to keep a variable of the index you're at, and check for IndexOf from there only (See MSDN). Something like this:
int index = 0;
while (quote.IndexOf(upKey, index) != -1)
{
//Your code, including updating the value of index.
}
(I didn't check this on Visual Studio. This is just to point you in the direction that I think you're looking for.)
The reason for the infinite loop is that you're always testing IndexOf of the same index. Perhaps you mean to have quote.IndexOf(upKey, index += 1); which would change the value of index?
The way to go here is to probably use Regex but these easy parsing excercises are always fun to do manually. This can be easily solved using a very simple state machine.
What states can we have when dealing with strings of this nature? I can think of 4:
We are either parsing normal text
Or we are parsing an opening format tag '<...>'
Or we are parsing a closing format tag '</...>'
Or we are parsing text to be formatted between tags
I can't think of any other states. Now we need to think about the normal flow / transition between states. What should happen when we a parse string with the correct format?
Parser starts up expecting normal text. That is easy to understand.
If expecting normal text we encounter a '<' then the parser should switch to parsing opening format tag state. There is no other valid state transition.
If in parsing opening format tag state we encounter a '>' then the parser should switch to parsing text to be formatted. There is no other valid state transition.
If in parsing text to be formatted we encounter a '<' then the parser should switch to parsing closing tag. Again, there is no other valid state transition.
If in parsing closing tag we encounter a '>' then the parser should switch to normal text. Once more, there is no other valid transition. Note that we are disallowing nested tags.
Ok, so that seems pretty easy to understand. What do we need to implement this?
First we'll need something to represent the parsing states. A good old enum will do:
private enum ParsingState
{
UnformattedText,
OpenTag,
CloseTag,
FormattedText,
}
Now we need some string buffers to keep track of the final formatted string, the current format tag we are parsing and finally the substring we need to format. We will use several StringBuilder's for these as we don't know how long these buffers are and how many concatenations will be performed:
var formattedStringBuffer = new StringBuilder();
var formatBuffer = new StringBuilder();
var tagBuffer = new StringBuilder();
We will also need to keep track of the parser's state and the current active tag if any (so we can make sure that the parsed closing tag matches the current active tag):
var state = ParsingState.UnformattedText;
var activeFormatTag = string.Empty;
And now we are good to go, but before we do, can we generalize this so it works with any format tag?
Yes we can, we just need to tell the parser what to do for each supported tag. We can do this easily just passing a along a Dictionary that ties each tag with the action it should perform. We do this the following way:
var formatter = new Dictionary<string, Func<string, string>>();
formatter.Add("upcase", s => s.ToUpperInvariant());
formatter.Add("lcase", s => s.ToLowerInvariant());
Great! Now our implementation could be the following:
public static string Parse(this string str, Dictionary<string, Func<string,string>> formatter)
{
var formattedStringBuffer = new StringBuilder();
var formatBuffer = new StringBuilder();
var tagBuffer = new StringBuilder();
var state = ParsingState.UnformattedText;
var activeFormatTag = string.Empty;
foreach (var c in str)
{
switch (state)
{
case ParsingState.UnformattedText:
{
if (c != '<')
{
formattedStringBuffer.Append(c);
}
else
{
state = ParsingState.OpenTag;
}
break;
}
case ParsingState.OpenTag:
{
if (c != '>')
{
tagBuffer.Append(c);
}
else
{
state = ParsingState.FormattedText;
activeFormatTag = tagBuffer.ToString();
tagBuffer.Clear();
}
break;
}
case ParsingState.FormattedText:
{
if (c != '<')
{
formatBuffer.Append(c);
}
else
{
state = ParsingState.CloseTag;
}
break;
}
case ParsingState.CloseTag:
{
if (c!='>')
{
tagBuffer.Append(c);
}
else
{
var expectedTag = $"/{activeFormatTag}";
var tag = tagBuffer.ToString();
if (tag != expectedTag)
throw new FormatException($"Expected closing tag not found: <{expectedTag}>.");
if (formatter.ContainsKey(activeFormatTag))
{
var formatted = formatter[activeFormatTag](formatBuffer.ToString());
formattedStringBuffer.Append(formatted);
tagBuffer.Clear();
formatBuffer.Clear();
state = ParsingState.UnformattedText;
}
else
throw new FormatException($"Format tag <{activeFormatTag}> not recognized.");
}
break;
}
}
}
if (state != ParsingState.UnformattedText)
throw new FormatException($"Bad format in specified string '{str}'");
return formattedStringBuffer.ToString();
}
Is it the most elegant solution? No, Regex will do a much better job, but being a beginner I would not recommend you start solving these kind of problems that way, you'll learn a whole lot more solving them manualy. You'll have plenty of time to learn Regex later on.
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.'.
The title explains it all. It seems simple enough, so I must be overlooking something stupid. Here's what I've got.
private string getBetween(string strSource, string strStart, string strEnd)
{
int start, end;
if (strSource.Contains(strStart) && strSource.Contains(strEnd))
{
start = strSource.IndexOf(strStart, 0) + strStart.Length;
end = strSource.IndexOf(strEnd, start);
return strSource.Substring(start, end - start);
}
else
{
return "";
}
}
Thanks, guys.
Your code doesn't make sure that start and end are in order.
static string SubString(string source, string prefix, string suffix)
{
int start = source.IndexOf(prefix); // get position of prefix
if (start == -1)
return String.Empty;
int subStart = start + prefix.Length; // get position of substring
int end = source.IndexOf(suffix, subStart); // make sure suffix also exists
if (end == -1)
return String.Empty;
int subLength = end - subStart; // calculate length of substring
if (subLength == 0)
return String.Empty;
return source.Substring(subStart, subLength); // return substring
}
As couple of peoples said the problem that you code is working on very specific input, it's all because of this start and end IndexOf magic =) But when you try to update you code to work correct on more inputs you will get into problem that your code become very long with many indexes, comparsions, substrings, conditions and so on. To avoid this i like to recommend you use regular expressions with theirs help you can express what you need on special language.
Here is the sample which solves your problem with regular expressions:
public static string getBetween(string source, string before, string after)
{
var regExp = new Regex(string.Format("{0}(?<needle>[^{0}{1}]+){1}",before,after));
var matches = regExp.Matches(source).Cast<Match>(). //here we use LINQ to
OrderBy(m => m.Groups["needle"].Value.Length). //find shortest string
Select(m => m.Groups["needle"].Value); //you can use foreach loop instead
return matches.FirstOrDefault();
}
All tricky part is {0}(?<needle>[^{0}{1}]+){1} where 0 - before string and 1 - after string. This expression means that we nned to find string that lies beetween 0 and 1, and also don't contains 0 and 1.
Hope this helps.
I get the correct answer if I try any of these:
var a = getBetween("ABC", "A", "C");
var b = getBetween("TACOBBURRITO", "TACO", "BURRITO");
var c = getBetween("TACOBACONBURRITO", "TACO", "BURRITO");
The problem is likely with your input argument validation, as this fails:
var a = getBetween("ABC", "C", "A");
var a = getBetween("ABC", "C", "C");
You can improve your validation of the issue by writing some test cases like these as a separate fixture (xUnit, or main loop in throw away app).
i just want to get a text from textbox that is betwen two dots for example. www. abc.org . h
in C#
string url = "www.google.com";
string[] split_strings = url.Split('.');
Console.WriteLine(split_strings[1]);
Get String From Textbox:
string url = textbox_url.Text;
string[] split_strings = url.Split('.');
Console.WriteLine(split_strings[1]);
But please, use try and catch ;)
You'll need to be a bit more specific with your question I think. Now, if you're just looking to extract the middle part of the address, something like the following should do the job:
var parts = textbox.Text.Split(new char[] {'.'});
if (parts.Length < 3) throw new InvalidOperationException("Invalid address.");
var middlePart = parts[1];
Is that as specific as your requirement is?
does it only have to work for www.SOMESITE.com
what about other tld extensions like, .net, .org, .co.uk, .ie etc...
what about other subdomains like, www2., api., news. etc...
what about domains with no subdomain like, google.com, theregister.co.uk, bit.ly
if that's a simple as your requirement is,
then
textBox.Text.Replace("www.", "").Replace(".com", "");
though I've a feeling you haven't thought through or fully explained your requirements.
If it is a more complex scenario, you might want to look at Regular expressions.
string haystack= "www.google.com";
string needle = "google";
string myWord = GetWordFromString(haystack, needle);
private string GetWordFromString(string haystack, string needle)
{
if (haystack.ToLower().Contains(needle))
{
return needle;
}
}
I re-read the post with comments I can see that you probably don't know what word you are going to extract... I think the first answer is the one that you are looking fore.
There's also regular expressions for extracting the domainname out of a url if that is your specific need.
Something like this:
public static string ExtractDomainName(string Url)
{
return System.Text.RegularExpressions.Regex.Replace(
Url,
#"^([a-zA-Z]+:\/\/)?([^\/]+)\/.*?$",
"$2"
);
}
string text = "www. abc.org . h";
int left = Math.Max(text.IndexOf('.'), 0),
right = Math.Min(text.LastIndexOf('.'), text.Length - 1);
string result = text.Substring(left+1, right - left-1).Trim();