For looping and string - c#

So I have a string, and in it, I want to replace last 3 chars with a dot. I did something but my result is not what I wanted it to be.
Here is my code:
string word = "To je";
for (int k = word.Length; k > (word.Length) - 3; k--)
{
string newWord = word.Replace(word[k - 1], '.');
Console.WriteLine(newWord);
}
The output I get is:
To j.
To .e
To.je But the output I want is: To... How do I get there? So the program is doing something similar to what I actually want it to do, but not quite. I've really been struggling with this and any help would be appreciated.

Look at this:
string newWord = word.Replace(word[k - 1], '.');
You're always replacing a single character from word... but word itself doesn't change, so on the next iteration the replacement has "gone".
You could use:
word = word.Replace(word[k - 1], '.');
(And then move the output to the end, just writing out word.)
However, note that this will replace all occurrences of any of the last three characters with a ..
The simplest way to fix all of this is to use Substring of course, but if you really want to loop, you could use a StringBuilder:
StringBuilder builder = new StringBuilder(word);
for (int k = word.Length; k > (word.Length) - 3; k--)
{
builder[k - 1] = '.';
}
word = builder.ToString();

You're replacing all instances of the character at each of those three last positions with a period. You only want to replace that one character at the end. "aaaaa" shouldn't become "....." but rather "aa...".
You're printing out newWord after calculating an intermediate value and then never doing anything with it, leaving word unchanged. You'll want to assign it back to word, after correctly adjusting the character in question.
Of course the far easier solution (both for you, and for the computer) is to simply concat a substring of the string you have that excludes the last three characters with three periods.

Assuming the string is always at least 3 characters, you could substring everything but the last three characters and then append the three dots (periods) to the end of that string.
string word = "To je";
string newWord = word.Substring(0, word.Length - 3); // Grabs everything but the last three chars
newWord += "..."; // Appends three dots at the end of the new string
Console.WriteLine(newWord);
Note: this assumes that the input string word is at least three characters. If you were to supply a shorter string, you would need to supply an extra check on the string's length.

If you don't need the original word afterwards
Using Jon Skeets method
string word = "To je";
word = word.Substring(0,word.Length - 3);
word += "...";
Console.WriteLine(word);

as #jon-skeet said, you could do this with substrings. Here are 3 ways that you could do this with substring.
You could use String.Concat
string word = "To je";
word = String.Concat(word.Substring(0,word.Length-3),"...");
Console.WriteLine(word);
You could use the + operator
string word2 = "To je";
word2 = word2.Substring(0,word.Length-3) + "...";
Console.WriteLine(word2);
You could use String.Format
string word3 = "To je";
word3 = String.Format("{0}...",word3.Substring(0,word.Length-3));
Console.WriteLine(word3);

I'm a bit late to the party but all of the other solutions posted so far do not elegantly handle the case that the string is shorter than the requested number of replacements, or an arbitrary number of replacements. Here is a general function for replacing the last n characters at the end of a string with a user specified value:
static String replace_last_n(String s, int nchars, char replacement='.')
{
nchars = Math.Min(s.Length, nchars > 0 ? nchars : 0);
return s.Substring(0, s.Length - nchars) + new String(replacement, nchars);
}
Console.WriteLine(replace_last_n("wow wow wow", 3));
Console.WriteLine(replace_last_n("wow", 3, 'x'));
Console.WriteLine(replace_last_n("", 3));
Console.WriteLine(replace_last_n("w", 3));
Console.WriteLine(replace_last_n("wow", 0));
Console.WriteLine(replace_last_n("wow", -2));
Console.WriteLine(replace_last_n("wow", 33, '-'));
Output:
wow wow ...
xxx
.
wow
wow
---

if (word.Length > 3)
Console.WriteLine(word.substring(0, word.Length - 3) + "...");
or something along those lines, no need for a loop!

Related

string.IndexOf search for whole word match

I am seeking a way to search a string for an exact match or whole word match. RegEx.Match and RegEx.IsMatch don't seem to get me where I want to be. Consider the following scenario:
namespace test
{
class Program
{
static void Main(string[] args)
{
string str = "SUBTOTAL 34.37 TAX TOTAL 37.43";
int indx = str.IndexOf("TOTAL");
string amount = str.Substring(indx + "TOTAL".Length, 10);
string strAmount = Regex.Replace(amount, "[^.0-9]", "");
Console.WriteLine(strAmount);
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}
}
The output of the above code is:
// 34.37
// Press any key to continue...
The problem is, I don't want SUBTOTAL, but IndexOf finds the first occurrence of the word TOTAL which is in SUBTOTAL which then yields the incorrect value of 34.37.
So the question is, is there a way to force IndexOf to find only an exact match or is there another way to force that exact whole word match so that I can find the index of that exact match and then perform some useful function with it. RegEx.IsMatch and RegEx.Match are, as far as I can tell, simply boolean searches. In this case, it isn't enough to just know the exact match exists. I need to know where it exists in the string.
Any advice would be appreciated.
You can use Regex
string str = "SUBTOTAL 34.37 TAX TOTAL 37.43";
var indx = Regex.Match(str, #"\WTOTAL\W").Index; // will be 18
My method is faster than the accepted answer because it does not use Regex.
string str = "SUBTOTAL 34.37 TAX TOTAL 37.43";
var indx = str.IndexOfWholeWord("TOTAL");
public static int IndexOfWholeWord(this string str, string word)
{
for (int j = 0; j < str.Length &&
(j = str.IndexOf(word, j, StringComparison.Ordinal)) >= 0; j++)
if ((j == 0 || !char.IsLetterOrDigit(str, j - 1)) &&
(j + word.Length == str.Length || !char.IsLetterOrDigit(str, j + word.Length)))
return j;
return -1;
}
You can use word boundaries, \b, and the Match.Index property:
var text = "SUBTOTAL 34.37 TAX TOTAL 37.43";
var idx = Regex.Match(text, #"\bTOTAL\b").Index;
// => 19
See the C# demo.
The \bTOTAL\b matches TOTAL when it is not enclosed with any other letters, digits or underscores.
If you need to count a word as a whole word if it is enclosed with underscores, use
var idx = Regex.Match(text, #"(?<![^\W_])TOTAL(?![^\W_])").Index;
where (?<![^\W_]) is a negative lookbehind that fails the match if there is a character other than a non-word and underscore immediately to the left of the current location (so, there can be a start of string position, or a char that is a not a digit nor letter), and (?![^\W_]) is a similar negative lookahead that only matches if there is an end of string position or a char other than a letter or digit immediately to the right of the current location.
If the boundaries are whitespaces or start/end of string use
var idx = Regex.Match(text, #"(?<!\S)TOTAL(?!\S)").Index;
where (?<!\S) requires start of string or a whitespace immediately on the left, and (?!\S) requires the end of string or a whitespace on the right.
NOTE: \b, (?<!...) and (?!...) are non-consuming patterns, that is the regex index does not advance when matching these patterns, thus, you get the exact positions of the word you search for.
To make the accepted answer a little bit safer (since IndexOf returns -1 for unmatched):
string pattern = String.Format(#"\b{0}\b", findTxt);
Match mtc = Regex.Match(queryTxt, pattern);
if (mtc.Success)
{
return mtc.Index;
}
else
return -1;
While this may be a hack that just works for only your example, try
string amount = str.Substring(indx + " TOTAL".Length, 10);
giving an extra space before total. As this will not occur with SUBTOTAL, it should skip over the word you don't want and just look for an isolated TOTAL.
I'd recommend the Regex solution from L.B. too, but if you can't use Regex, then you could use String.LastIndexOf("TOTAL"). Assuming the TOTAL always comes after SUBTOTAL?
http://msdn.microsoft.com/en-us/library/system.string.lastindexof(v=vs.110).aspx

Remove a single space from a string

"How do I do this? "
Let's say I have this string. How do I remove only one space from the end? The code shown below gives me an error saying the count is out of range.
string s = "How do I do this? ";
s = s.Remove(s.Length, 1);
You just have to use this instead :
string s = "How do I do this? ";
s = s.Remove(s.Length-1, 1);
As stated here:
Remove(Int32) Returns a new string in which all the characters in the current
instance, beginning at a specified position and continuing through the
last position, have been deleted.
In an array, positions range from 0 to Length-1, hence the compiler error.
The indexing in C# are zero-based.
s = s.Remove(s.Length - 1, 1);
Just do a substring from the first character (chars are 0-based in string) and get number of chars less the string length by 1
s = s.Substring(0, s.Length - 1);
This is a little safer, just in case the last character is not a space
string s = "How do I do this? ";
s = Regex.Replace(s, #" $", "")
You have to write something in the lines of
string s = "How do I do this?
s = s.Remove(s.Length-1, 1);
Reason being that in C# when referring to indexes in arrays the first element is always at position 0 and end at Length - 1. The Length generally tells you how long a string is but doesn't map to the actual array index.
Another way to do it is;
string s = "How do I do this? ";
s=s.SubString(0,s.Length-1);
Additional :
If you would like do some additional checking for the last character being a space or anything,you can do it in this way;
string s = "How do I do this? a";//Just for example,i've added a 'a' at the end.
int index = s.Length - 1;//Get last Char index.
if (index > 0)//If index exists.
{
if (s[index] == ' ')//If the character at 'index' is a space.
{
MessageBox.Show("Its a space.");
}
else if (char.IsLetter(s[index]))//If the character at 'index' is a letter.
{
MessageBox.Show("Its a letter.");
}
else if(char.IsDigit(s[index]))//If the character at 'index' is a digit.
{
MessageBox.Show("Its a digit.");
}
}
This gives you a MessageBox with message "Its a letter".
One more thing that might be helpful,if you want to create a string with equal no. of spaces between each word,then you can try this.
string s = "How do I do this? ";
string[] words = s.Split(new char[] {' '},StringSplitOptions.RemoveEmptyEntries);//Break the string into individual words.
StringBuilder sb = new StringBuilder();
foreach (string word in words)//Iterate through each word.
{
sb.Append(word);//Append the word.
sb.Append(" ");//Append a single space.
}
MessageBox.Show(sb.ToString());//Resultant string 'sb.ToString()'.
This gives you "How do I do this? " (equal spaces between words).

Regular expression to split long strings in several lines

I'm not an expert in regular expressions and today in my project I face the need to split long string in several lines in order to check if the string text fits the page height.
I need a C# regular expression to split long strings in several lines by "\n", "\r\n" and keeping 150 characters by line maximum. If the character 150 is in the middle of an word, the entire word should be move to the next line.
Can any one help me?
It's actually a quite simple problem. Look for any characters up to 150, followed by a space. Since Regex is greedy by nature it will do exactly what you want it to. Replace it by the Match plus a newline:
.{0,150}(\s+|$)
Replace with
$0\r\n
See also: http://regexhero.net/tester/?id=75645133-1de2-4d8d-a29d-90fff8b2bab5
var regex = new Regex(#".{0,150}", RegexOptions.Multiline);
var strings = regex.Replace(sourceString, "$0\r\n");
Here you go:
^.{1,150}\n
This will match the longest initial string like this.
if you just want to split a long string into lines of 150 chars then I'm not sure why you'd need a regular expression:
private string stringSplitter(string inString)
{
int lineLength = 150;
StringBuilder sb = new StringBuilder();
while (inString.Length > 0)
{
var curLength = inString.Length >= lineLength ? lineLength : inString.Length;
var lastGap = inString.Substring(0, curLength).LastIndexOfAny(new char[] {' ', '\n'});
if (lastGap == -1)
{
sb.AppendLine(inString.Substring(0, curLength));
inString = inString.Substring(curLength);
}
else
{
sb.AppendLine(inString.Substring(0, lastGap));
inString = inString.Substring(lastGap + 1);
}
}
return sb.ToString();
}
edited to account for word breaks
This code should help you. It will check the length of the current string. If it is greater than your maxLength (150) in this case, it will start at the 150th character and (going backwards) find the first non-word character (as described by the OP, this is a sequence of non-space characters). It will then store the string up to that character and start over again with the remaining string, repeating until we end up with a substring that is less than maxLength characters. Finally, join them all back together again in a final string.
string line = "This is a really long run-on sentence that should go for longer than 150 characters and will need to be split into two lines, but only at a word boundary.";
int maxLength = 150;
string delimiter = "\r\n";
List<string> lines = new List<string>();
// As long as we still have more than 'maxLength' characters, keep splitting
while (line.Length > maxLength)
{
// Starting at this character and going backwards, if the character
// is not part of a word or number, insert a newline here.
for (int charIndex = (maxLength); charIndex > 0; charIndex--)
{
if (char.IsWhiteSpace(line[charIndex]))
{
// Split the line after this character
// and continue on with the remainder
lines.Add(line.Substring(0, charIndex+1));
line = line.Substring(charIndex+1);
break;
}
}
}
lines.Add(line);
// Join the list back together with delimiter ("\r\n") between each line
string final = string.Join(delimiter , lines);
// Check the results
Console.WriteLine(final);
Note: If you run this code in a console application, you may want to change "maxLength" to a smaller number so that the console doesn't wrap on you.
Note: This code does not take into effect any tab characters. If tabs are also included, your situation gets a bit more complicated.
Update: I fixed a bug where new lines were starting with a space.

C# program to find no of words that can be generated from a word by adding ' . ' in between characters?

I asked this question in the chat room. but no answer so i am posting the question here.
The question is, for example take the word abcd
it has 4 charcters. by adding the ' . ' in between the characters you can write it as a.b.c.d
rules
can use only 1 dot between characters
can use multiple dots in the word
Edit: there can be characters without ' . ' in between them. eg (ab or abcd)
cannot use dot at the beginning or end of the word ie .abcd or abcd. are false
some of the answers
a.b.c.d
a.bcd
ab.cd
abc.d
a.b.cd
a.bc.d
ab.c.d
abc.d
how many word are possible to make. how to write a program to find it in c# ?
Edit
how to display each possible word ?
You don't really need to write a program for this.
For a word of n characters, there are n-1 positions where there can be a dot (i.e. between each pair of characters). Each position either has a dot or doesn't.
There are therefore 2n-1 possible words.
If you really want to write a C# program to display this:
using System;
class Test
{
static void Main(string[] args)
{
// Argument validation left as an exercise for the reader
string word = args[0];
Console.WriteLine("Word {0} has {1} possibilities",
word, Math.Pow(2, word.Length - 1));
}
}
EDIT: Note that this assumes that the original word (with no dots) still counts. If you don't want it to count, subtract one from the result.
EDIT: I've changed the computation to use Math.Pow so that:
It copes with words with more than 33 letters (up to another limit, of course)
It's clearer
You can do it recursively.
All possible combinations of (abcd) are:
a + . + all combinations of (bcd)
ab + . + all combinations of (cd)
abc + . + all combinations of (d)
abcd
Code:
public static IEnumerable<string> GetCombinations(string str) {
for (int i = 1; i < str.Length; i++) {
foreach (string s in GetCombinations(str.Substring(i))) {
yield return str.Substring(0, i) + "." + s;
}
}
yield return str;
}
Usage:
foreach (string s in GetCombinations("abcd")) Console.WriteLine(s);
Number of combinations:
string s = "abcd";
int len = s.Length;
int combinations = 1 << (len - 1);
EDIT: as Paul notes in the comments,
int combinations = 1 << (len - 1) - 1;
to remove the word that contains no dots if that's not a valid combination.
Why do you need a program?
if the string is length n, then there are n-1 places you can put a .
In any place, there can either be a . or not, that is, two options.
SO the answer is 2**(n-1) - 1 (the -1 being for the answer that has no dots, i.e the original word)

How to remove words based on a word count

Here is what I'm trying to accomplish. I have an object coming back from
the database with a string description. This description can be up to 1000
characters long, but we only want to display a short view of this. So I coded
up the following, but I'm having trouble in actually removing the number of
words after the regular expression finds the total count of words. Does anyone
have good way of dispalying the words which are less than the Regex.Matches?
Thanks!
if (!string.IsNullOrEmpty(myObject.Description))
{
string original = myObject.Description;
MatchCollection wordColl = Regex.Matches(original, #"[\S]+");
if (wordColl.Count < 70) // 70 words?
{
uxDescriptionDisplay.Text =
string.Format("<p>{0}</p>", myObject.Description);
}
else
{
string shortendText = original.Remove(200); // 200 characters?
uxDescriptionDisplay.Text =
string.Format("<p>{0}</p>", shortendText);
}
}
EDIT:
So this is what I got working on my own:
else
{
int count = 0;
StringBuilder builder = new StringBuilder();
string[] workingText = original.Split(' ');
foreach (string word in workingText)
{
if (count < 70)
{
builder.AppendFormat("{0} ", word);
}
count++;
}
string shortendText = builder.ToString();
}
It's not pretty, but it worked. I would call it a pretty naive way of doing this. Thanks for all of the suggestions!
I would opt to go by a strict character count rather than a word count because you might happen to have a lot of long words.
I might do something like (pseudocode)
if text.Length > someLimit
find first whitespace after someLimit (or perhaps last whitespace immediately before)
display substring of text
else
display text
Possible code implementation:
string TruncateText(string input, int characterLimit)
{
if (input.Length > characterLimit)
{
// find last whitespace immediately before limit
int whitespacePosition = input.Substring(0, characterLimit).LastIndexOf(" ");
// or find first whitespace after limit (what is spec?)
// int whitespacePosition = input.IndexOf(" ", characterLimit);
if (whitespacePosition > -1)
return input.Substring(0, whitespacePosition);
}
return input;
}
One method, if you're using at least C#3.0, would be a LINQ like the following. This is provided you're going strictly by word count, not character count.
if (wordColl.Count > 70)
{
foreach (var subWord in wordColl.Cast<Match>().Select(r => r.Value).Take(70))
{
//Build string here out of subWord
}
}
I did a test using a simple Console.WriteLine with your Regex and your question body (which is over 70 words, it turns out).
You can use Regex Capture Groups to hold the match and access it later.
For your application, I'd recommend instead simply splitting the string by spaces and returning the first n elements of the array:
if (!string.IsNullOrEmpty(myObject.Description))
{
string original = myObject.Description;
string[] words = original.Split(' ');
if (words.Length < 70)
{
uxDescriptionDisplay.Text =
string.Format("<p>{0}</p>", original);
}
else
{
string shortDesc = string.Empty;
for(int i = 0; i < 70; i++) shortDesc += words[i] + " ";
uxDescriptionDisplay.Text =
string.Format("<p>{0}</p>", shortDesc.Trim());
}
}
Are you wanting to remove 200 characters or start truncating at the 200th character? When you call original.Remove(200) you are indexing the start of the truncation at the 200th character. This is how you use Remove() for a certain number of characters to remove:
string shortendText = original.Remove(0,200);
This starts at the first character and removes 200 starting with that one. Which I imagine that's not what you're trying to do since you're shortening a description. That's merely the correct way to use Remove().
Instead of using Regex matchcollections why not just split the string? It's a lot easier and straight forward. You can set the delimiter to a space character and split that way. Not sure if that completely fixes your need but it just might. I'm not sure what your data looks like in the description. But you split this way:
String[] wordArray = original.Split(' ');
From there you can determine the word count with wordArray's Length property value.
If I was you I would go by characters as you may have many one letter words or many long words in your text.
Go through until characters <= your limit, then either find the next space and then add these characters to a new string (possibly using the SubString method) or take these characters and add a few full stops, then make a new string The later could be unproffessional I suppose.

Categories

Resources