C# String.Format Characters - c#

Just starting to muddle my way through C# and I have a question which maybe really simple (Once somebody explains it to me).
I have a text box asking for the users National Insurance Number (This is program doesn't do anything it's just me trying to figure out the formatting sequences) - But I'm pulling my hair out trying to work out how to display this back to the label.
at the moment I have the following
string result = String.Format("Thank you, {0}"+
" for your business. You NI # is {1:???}",
nameTextBox.Text,
socialTextBox.Text);
resultLabel.Text = result;
I don't know what to replace the ? with.. Any help would be really appreciated.
Many Thanks

I was looking for something like BN-201285-T
You could make your own function that formats the string to the desired format :
private string CustomFormat(string input) {
return string.Format("BN-{0}-T", input);
}
Then pass the formated string to the string.Format call :
string result = String.Format("Thank you, {0}" +
" for your business. You NI # is {1}",
nameTextBox.Text,
CustomFormat(socialTextBox.Text));
resultLabel.Text = result;

Related

C# IndexOf function not working as expected

So, I'm fairly new to coding, but I've never had a problem with IndexOf until now. I'm trying to search through an html string which looks like:
" data-pid=\"6598160343\">\n\n https://minneapolis.craigslist.org/dak/fuo/d/executive-desk-3-piece-set/6598160343.html\"
class=\"result-image gallery\"
data-ids=\"1:00B0B_hkRi5TEyM9Q,1:00z0z_jTtBxHxlxAZ,1:00p0p_2GU15WOHDEB,1:00909_eKQVd7O1pfE\">\n
$1500\n \n\n \n \n favorite this post\n
\n\n Jun
4\n\n\n https://minneapolis.craigslist.org/dak/fuo/d/executive-desk-3-piece-set/6598160343.html\"
data-id=\"6598160343\" class=\"result-title hdrlnk\">Executive Desk (3
piece set)\n\n\n \n
$1500\n\n\n\n \n pic\n
map\n
\n\n \n hide this posting\n
\n\n \n \n restore\n restore this posting\n
\n\n \n \n\n " string
I'm trying to find the index of specific elements so that I can grab the data later, here's what I have to find the indexes of the positions on either side of the data I want:
DataBookends bkEnds = new DataBookends
{
PIDFrom = (post.IndexOf(#"pid=\""")) + (#"pid=\""".Length),
URLFrom = (post.IndexOf(#"<a href=\")) + (#"<a href=\".Length),
PriceFrom = (post.IndexOf(#"result-price\"">$")) + (#"result-price\"">$".Length),
DateFrom = (post.IndexOf(#"datetime=\""")) + (#"datetime=\""".Length),
TitleFrom = (post.IndexOf(#"result-title hdrlnk\"">")) + (#"result-title hdrlnk\"">".Length),
LocationFrom = (post.IndexOf(#"result-hood\""> (")) + (#"result-hood\""> (".Length)
};
bkEnds.PIDTo = post.IndexOf(#"\""", bkEnds.PIDFrom);
bkEnds.URLTo = post.IndexOf(#"\", bkEnds.URLFrom);
bkEnds.PriceTo = post.IndexOf(#"</span>", bkEnds.PriceFrom);
bkEnds.DateTo = post.IndexOf(#"\", bkEnds.DateFrom);
bkEnds.TitleTo = post.IndexOf(#"</a>", bkEnds.TitleTo);
bkEnds.LocationTo = post.IndexOf(#"\", bkEnds.LocationFrom);
return bkEnds;
However, whenever I try to run it, it either doesn't find anything, or the index values are incorrect. I know I'm missing something simple but I can't figure it out and I feel like a moron. Is it something to do with escape characters I'm not seeing or something with how my string is formatted?
Help please?
EDIT:
I initially tried using the HTML Agility Pack, but I was having trouble understanding how to extract the data I needed so I thought using string.substring() would've been more straightforward.
The index values I'm getting are entirely wrong, even before I tried adding the forward-slashes. I'll be getting rid of those.
I'll write this answer but really it was CraigW in the comments who spotted your error. I think it could still use some explaining as you missed it. Also, the other comments are right that a parser might be the way to go. I still think you should understand the mistake you made as it's generally useful.
You said the variable has this string
" data-pid=\"6598160343\">\n\n https://minneapolis.craigslist.org/dak/fuo/d/executive-desk-3-piece-set/6598160343.html\" class=\"result-image gallery\" data-ids=\"1:00B0B_hkRi5TEyM9Q,1:00z0z_jTtBxHxlxAZ,1:00p0p_2GU15WOHDEB,1:00909_eKQVd7O1pfE\">\n $1500\n \n\n \n \n favorite this post\n
\n\n Jun 4\n\n\n https://minneapolis.craigslist.org/dak/fuo/d/executive-desk-3-piece-set/6598160343.html\" data-id=\"6598160343\" class=\"result-title hdrlnk\">Executive Desk (3 piece set)\n\n\n \n
$1500\n\n\n\n \n pic\n
map\n
\n\n \n hide this posting\n
\n\n \n \n restore\n restore this posting\n
\n\n \n
\n\n " string
which seems to have come from the debugger. You're searching with
post.IndexOf(#"pid=\""")
this won't find a hit, because it is literally looking for pid=\" which is not in your variable. Your variable actually contains
data-pid="6598160343">
https://minneap....
The debugger showed it as
data-pid=\"6598160343\">\n\n https://minneap
because it always 'escapes' quotes (ie a " in the variable shows in the watch window as \") and similarly newlines appear as \n. If you click the magnifying glass icon you will see the string as it really is, without the escapes.
Hope that clears your confusion, if it does you will now realise that this code would work
post.IndexOf(#"pid=""")
Also, for your interest note that if you don't use # before a string then you escape the ", eg.
post.IndexOf("pid=\"")
I think you can change your code a little bit because it's really hard to debug. See my code below and get your idea. You can copy and paste the method ExtractData (and the class as well) to your code, but you need to add some code to verify the patterStart, patterEnd can be found from the content
using System;
public static class StringFinder
{
public static string ExtractData(this string content, string patterStart, string patternEnd)
{
var indexStart = content.IndexOf(patterStart) + patterStart.Length;
var indexEnd = content.IndexOf(patternEnd, indexStart);
return content.Substring(indexStart,indexEnd - indexStart);
}
}
public class Program
{
public static void Main()
{
var data = #" data-pid=\""6598160343\"">\n\n https://minneapolis.craigslist.org/dak/fuo/d/executive-desk-3";
Console.WriteLine(data.ExtractData(#"data-pid=\""", #"\"">"));
}
}
Result 6598160343
So I figured it out, I ended up going with HTML Agility Pack as was suggested by Jeremy. I wasn't able to figure out what exactly was wrong with how I was searching through it with IndexOf and Substring (for example: it would skip "" and continue on until a point that didn't contain any of those characters), but I'm not going to try web-scraping that way again.
For the future, HTML Agility Pack is the way to go!

Getting a part of a string and outputting it to another string

Hi so i'm not exactly sure if the title justifies this question I'm not too good at phrasing sorry.
But what i'm trying to do is um like:
String joggingResults = ",Distance: 2.4km, Duration: 14minutes,";
And ideally, I would like to search joggingResults for " , " and output the words beside it.. and stops when it finds another " , " ... Does this make any sense? haha
My expected result would be something like this but each line is on a new string:
Distance: 2.4km
Duration: 14minutes
I hope someone helps me out tysm
You can split using ',' and then loop through the array and display the results.
var results = joggingResults.Split(',');
foreach(var item in results)
{
Console.WriteLine(item);
}
Note:- Assuming it is a console application. You can display it as per your type of application.
joggingResults.Split(',')
Will give you a collection of strings split where the commas are.

String comparison fails even when visually checked

I added a function to my application recently that reads a date from a downloaded file and finds the difference in days between current date and the date from the file. When done, it is displayed in a label in one of my forums.
There is an exception: if the string in the file equals "Lifetime", it should not process it as a date and follow alternate logic. But when I try to check if the string is "Lifetime", it does not return true, even if the string = "Lifetime".
EDIT: I fixed the FormatException with help from Nisarg. Now, my labels aren't changing to the values. This is the problem.
EDIT2: I feel stupid. I found out that I was initiating Main twice in one function, then using main1 to switch between forms and main to set the labels.
This is why the labels weren't working right. Thanks Nisarg and all other contributors.
Code example:
string subScript = File.ReadAllText(Path.GetTempPath() + txtUsername.Text + ".txt");
Main main = new Main();
double dSubLeft;
main.dateLabel.Text = subScript;
if (subScript == "Lifetime") // it bypasses this, apparently blank
{
main.daysLeftLabel.Text = "Expires: Never";
}
if (subScript != "Lifetime") //Goes here and throws error saying subScript is not valid DateTime
{
dSubLeft = Math.Round(Convert.ToDouble(Convert.ToString(((Convert.ToDateTime(subScript)) - DateTime.Now).TotalDays)));
string sSubLeft = Convert.ToString(dSubLeft);
main.daysLeftLabel.Text = "Expires: " + sSubLeft + " Days";
}
While using files you often get trailing blank spaces or newline characters. Try trimming the string before comparing it to Lifetime:
subScript = subScript.Trim().Trim(Environment.NewLine.ToCharArray());
Another (less likely) problem could be with the comparison itself. In C# the comparison in case-sensitive. So if you're comparing lifetime with Lifetime they are considered unequal. You should rather use case-insensitive comparison:
if(string.Equals(subScript, "Lifetime", StringComparer.OrdinalIgnoreCase))
OR
if(subScript.ToLower() == "lifetime")
You could also check if the subScript you are getting from the file is a valid date or not using DateTime.TryParse.
string subScript = File.ReadAllText(Path.GetTempPath() + txtUsername.Text + ".txt");
Main main = new Main();
double dSubLeft;
main.dateLabel.Text = subScript;
DateTime subScriptDate;
if(!DateTime.TryParse(subScript, out subScriptDate))
{
main.daysLeftLabel.Text = "Expires: Never";
}
else //Goes here and throws error saying subScript is not valid DateTime
{
dSubLeft = Math.Round(Convert.ToDouble(Convert.ToString((subScriptDate - DateTime.Now).TotalDays)));
string sSubLeft = Convert.ToString(dSubLeft);
main.daysLeftLabel.Text = "Expires: " + sSubLeft + " Days";
}
I think it is because main is the starting point of a program in C#, make another methodname if you don´t want it to reset things from where the program is supposed to start from
That is my guess only, make a breakpoint in the beginning of your code and check through what info you get from each row in the code
Almost certainly, the actual content of the string is not actually the string "Lifetime". Probably because of white-space on either side. Try trimming.
Relevant edit:
if (subscript.Trim() == "Lifetime")
{
main.daysLeftLabel.Text = "Expires: Never";
}
else // don't retest for the opposite condition
{
...
As you can see, this thing is awfully fragile, because the string could still be many things that aren't a valid DateTime. Smells like homework, but there you go...
i think you should use
if(string.Equals(subScript, "Lifetime", StringComparer.OrdinalIgnoreCase))
{
//statement
}
else
{
//statement
}

Extract sub-string between two certain words right to left side

Example String
This is an important example about regex for my work.
I can extract important example about regex with this (?<=an).*?(?=for) snippet. Reference
But i would like to extract to string right to left side. According to this question's example; first position must be (for) second position must be (an).
I mean extracting process works back ways.
I tried what i want do as below codes in else İf case, but it doesn't work.
public string FnExtractString(string _QsString, string _QsStart, string _QsEnd, string _QsWay = "LR")
{
if (_QsWay == "LR")
return Regex.Match(_QsString, #"(?<=" + _QsStart + ").*?(?=" + _QsEnd + ")").Value;
else if (_QsWay == "RL")
return Regex.Match(_QsString, #"(?=" + _QsStart + ").*?(<=" + _QsEnd + ")").Value;
else
return _QsString;
}
Thanks in advance.
EDIT
My real example as below
#Var|First String|ID_303#Var|Second String|ID_304#Var|Third String|DI_t55
When i pass two string to my method (for example "|ID_304" and "#Var|") I would like to extract "Second String" but this example is little peace of my real string and my string is changeable.
No need for forward or backward lookahead! You could just:
(.*)\san\s.*\sfor\s
The \s demands whitespace, so you don't match an import*an*t.
One potential problem in your current solution is that the string passed in contains special characters, which needs to be escaped with Regex.Escape before concatenation:
return Regex.Match(_QsString, #"(?<=" + Regex.Escape(_QsStart) + ").*?(?=" + Regex.Escape(_QsEnd) + ")").Value;
For your other requirement of matching RL, I don't understand your requirement.

.NET String parsing performance improvement - Possible Code Smell

The code below is designed to take a string in and remove any of a set of arbitrary words that are considered non-essential to a search phrase.
I didn't write the code, but need to incorporate it into something else. It works, and that's good, but it just feels wrong to me. However, I can't seem to get my head outside the box that this method has created to think of another approach.
Maybe I'm just making it more complicated than it needs to be, but I feel like this might be cleaner with a different technique, perhaps by using LINQ.
I would welcome any suggestions; including the suggestion that I'm over thinking it and that the existing code is perfectly clear, concise and performant.
So, here's the code:
private string RemoveNonEssentialWords(string phrase)
{
//This array is being created manually for demo purposes. In production code it's passed in from elsewhere.
string[] nonessentials = {"left", "right", "acute", "chronic", "excessive", "extensive",
"upper", "lower", "complete", "partial", "subacute", "severe",
"moderate", "total", "small", "large", "minor", "multiple", "early",
"major", "bilateral", "progressive"};
int index = -1;
for (int i = 0; i < nonessentials.Length; i++)
{
index = phrase.ToLower().IndexOf(nonessentials[i]);
while (index >= 0)
{
phrase = phrase.Remove(index, nonessentials[i].Length);
phrase = phrase.Trim().Replace(" ", " ");
index = phrase.IndexOf(nonessentials[i]);
}
}
return phrase;
}
Thanks in advance for your help.
Cheers,
Steve
This appears to be an algorithm for removing stop words from a search phrase.
Here's one thought: If this is in fact being used for a search, do you need the resulting phrase to be a perfect representation of the original (with all original whitespace intact), but with stop words removed, or can it be "close enough" so that the results are still effectively the same?
One approach would be to tokenize the phrase (using the approach of your choice - could be a regex, I'll use a simple split) and then reassemble it with the stop words removed. Example:
public static string RemoveStopWords(string phrase, IEnumerable<string> stop)
{
var tokens = Tokenize(phrase);
var filteredTokens = tokens.Where(s => !stop.Contains(s));
return string.Join(" ", filteredTokens.ToArray());
}
public static IEnumerable<string> Tokenize(string phrase)
{
return string.Split(phrase, ' ');
// Or use a regex, such as:
// return Regex.Split(phrase, #"\W+");
}
This won't give you exactly the same result, but I'll bet that it's close enough and it will definitely run a lot more efficiently. Actual search engines use an approach similar to this, since everything is indexed and searched at the word level, not the character level.
I guess your code is not doing what you want it to do anyway. "moderated" would be converted to "d" if I'm right. To get a good solution you have to specify your requirements a bit more detailed. I would probably use Replace or regular expressions.
I would use a regular expression (created inside the function) for this task. I think it would be capable of doing all the processing at once without having to make multiple passes through the string or having to create multiple intermediate strings.
private string RemoveNonEssentialWords(string phrase)
{
return Regex.Replace(phrase, // input
#"\b(" + String.Join("|", nonessentials) + #")\b", // pattern
"", // replacement
RegexOptions.IgnoreCase)
.Replace(" ", " ");
}
The \b at the beginning and end of the pattern makes sure that the match is on a boundary between alphanumeric and non-alphanumeric characters. In other words, it will not match just part of the word, like your sample code does.
Yeah, that smells.
I like little state machines for parsing, they can be self-contained inside a method using lists of delegates, looping through the characters in the input and sending each one through the state functions (which I have return the next state function based on the examined character).
For performance I would flush out whole words to a string builder after I've hit a separating character and checked the word against the list (might use a hash set for that)
I would create A Hash table of Removed words parse each word if in the hash remove it only one time through the array and I believe that creating a has table is O(n).
How does this look?
foreach (string nonEssent in nonessentials)
{
phrase.Replace(nonEssent, String.Empty);
}
phrase.Replace(" ", " ");
If you want to go the Regex route, you could do it like this. If you're going for speed it's worth a try and you can compare/contrast with other methods:
Start by creating a Regex from the array input. Something like:
var regexString = "\\b(" + string.Join("|", nonessentials) + ")\\b";
That will result in something like:
\b(left|right|chronic)\b
Then create a Regex object to do the find/replace:
System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(regexString, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
Then you can just do a Replace like so:
string fixedPhrase = regex.Replace(phrase, "");

Categories