I noticed that the fully qualified name of an object I had written was coming back funny. While stepping through my ToString() method, I noticed that when it came to concatenating the string, a character object was consistently being left out of that process.
Here's a step through of what's happening
Before
After
Where Char seperator = ':';
Here's the code of my tostring function:
public String ToString(Representaion rep)
{
String toReturn = "kuid";
Char separator = ':';
switch (rep)
{
case Representaion.Colons:
break;
case Representaion.Underscores:
separator = '_';
break;
case Representaion.UCROnly:
toReturn = userID + ":" + contentID;
toReturn += revision == 0 ? "" : ":" + revision;
return toReturn;
}
toReturn += version == 0 ? "" : version.ToString();
toReturn += separator + userID + separator + contentID;
toReturn += revision == 0 ? "" : separator + revision.ToString();
return toReturn;
}
Where you have
private byte version;
private int userID;
private int contentID;
private byte revision;
And one case may look like this:
Already, looking in the locals panel, it seems like VS is getting a string other than what I think it would.
I put in another ToString function to handle a call without parameters (which it does by calling the parametrized function with Representation.Colons):
public override string ToString()
{
return this.ToString(KUID.Representaion.Colons);
}
Can anyone tell why I'm not getting what I think I should be getting? (Expected result: kuid2:72938:40175:2)
Now that you've posted more of your program the problem is obvious. Char plus int is not string. Remember,
string += char + int + char + int
means:
string = string + (((char + int ) + char) + int)
And when you add an int to a char, you get an int: 'a' + 2 produces the integer character code corresponding to 'c', not the string "a2".
You're getting some crazy integer by adding the user id to the colon char.
Concatenating strings like this is a bad practice for exactly the reason you have run into. Instead, say:
return string.Format("kuid{0}{1}{2}{3}{4}{5}{6}",
version, separator, userID, separator, contentID,
revision == 0 ? "" : separator.ToString(),
revision == 0 ? "" : revision.ToString());
Or, even better, use a StringBuilder object to build a complicated string.
Incidentally, this illustrates an interesting point about the language:
a += b + c;
does not mean
a = (a + b) + c;
It means
a = a + (b + c);
which as we've seen, might have a different type analysis! Had you said:
string = string + char + int + char + int
then that would have been analyzed as
string = ((((string + char) + int) + char ) + int;
Which does make everything a string.
I copy pasted your code and it works fine
The problem happens, because the expression to the right is not a string expression. You are working with characters and integers which are not automatically converted to a string, unless they are used within a string expression. You can make it a string expression by starting with a string (here an empty string):
toReturn += "" + separator + userID + separator + contentID;
Related
I have a string of text and want to ensure that it contains at most one single occurrence of a specific character (,). Therefore I want to keep the first one, but simply remove all further occurrences of that character.
How could I do this the most elegant way using C#?
This works, but not the most elegant for sure :-)
string a = "12,34,56,789";
int pos = 1 + a.IndexOf(',');
return a.Substring(0, pos) + a.Substring(pos).Replace(",", string.Empty);
You could use a counter variable and a StringBuilder to create the new string efficiently:
var sb = new StringBuilder(text.Length);
int maxCount = 1;
int currentCount = 0;
char specialChar = ',';
foreach(char c in text)
if(c != specialChar || ++currentCount <= maxCount)
sb.Append(c);
text = sb.ToString();
This approach is not the shortest but it's efficient and you can specify the char-count to keep.
Here's a more "elegant" way using LINQ:
int commasFound = 0; int maxCommas = 1;
text = new string(text.Where(c => c != ',' || ++commasFound <= maxCommas).ToArray());
I don't like it because it requires to modify a variable from a query, so it's causing a side-effect.
Regular expressions are elegant, right?
Regex.Replace("Eats, shoots, and leaves.", #"(?<=,.*),", "");
This replaces every comma, as long as there is a comma before it, with nothing.
(Actually, it's probably not elegant - it may only be one line of code, but it may also be O(n^2)...)
If you don't deal with large strings and you reaaaaaaly like Linq oneliners:
public static string KeepFirstOccurence (this string #string, char #char)
{
var index = #string.IndexOf(#char);
return String.Concat(String.Concat(#string.TakeWhile(x => #string.IndexOf(x) < index + 1)), String.Concat(#string.SkipWhile(x=>#string.IndexOf(x) < index)).Replace(#char.ToString(), ""));
}
You could write a function like the following one that would split the string into two sections based on the location of what you were searching (via the String.Split() method) for and it would only remove matches from the second section (using String.Replace()) :
public static string RemoveAllButFirst(string s, string stuffToRemove)
{
// Check if the stuff to replace exists and if not, return the original string
var locationOfStuff = s.IndexOf(stuffToRemove);
if (locationOfStuff < 0)
{
return s;
}
// Calculate where to pull the first string from and then replace the rest of the string
var splitLocation = locationOfStuff + stuffToRemove.Length;
return s.Substring(0, splitLocation) + (s.Substring(splitLocation)).Replace(stuffToRemove,"");
}
You could simply call it by using :
var output = RemoveAllButFirst(input,",");
A prettier approach might actually involve building an extension method that handled this a bit more cleanly :
public static class StringExtensions
{
public static string RemoveAllButFirst(this string s, string stuffToRemove)
{
// Check if the stuff to replace exists and if not, return the
// original string
var locationOfStuff = s.IndexOf(stuffToRemove);
if (locationOfStuff < 0)
{
return s;
}
// Calculate where to pull the first string from and then replace the rest of the string
var splitLocation = locationOfStuff + stuffToRemove.Length;
return s.Substring(0, splitLocation) + (s.Substring(splitLocation)).Replace(stuffToRemove,"");
}
}
which would be called via :
var output = input.RemoveAllButFirst(",");
You can see a working example of it here.
static string KeepFirstOccurance(this string str, char c)
{
int charposition = str.IndexOf(c);
return str.Substring(0, charposition + 1) +
str.Substring(charposition, str.Length - charposition)
.Replace(c, ' ').Trim();
}
Pretty short with Linq; split string into chars, keep distinct set and join back to a string.
text = string.Join("", text.Select(c => c).Distinct());
I have strings that look like this:
1.23.4.34
12.4.67
127.3.2.21.3
1.1.1.9
This is supposed to be a collection of numbers, separated by '.' symbols, similar to an ip address. I need to increment only the last digit/digits.
Expected Output:
1.23.4.35
12.4.68
127.3.2.21.4
1.1.1.10
Basically, increment whatever the number that is after the last '.' symbol.
I tried this:
char last = numberString[numberString.Length - 1];
int number = Convert.ToInt32(last);
number = number + 1;
If I go with the above code, I just need to replace the characters after the last '.' symbol with the new number. How do I get this done, good folks? :)
It seems to me that one method would be to:
split the string on . to get an array of components.
turn the final component into an integer.
increment that integer.
turn it back into a string.
recombine the components with . characters.
See, for example, the following program:
using System;
namespace ConsoleApplication1 {
class Program {
static void Main(string[] args) {
String original = "1.23.4.34";
String[] components = original.Split('.');
int value = Int32.Parse(components[components.Length - 1]) + 1;
components[components.Length - 1] = value.ToString();
String newstring = String.Join(".",components);
Console.WriteLine(newstring);
}
}
}
which outputs the "next highest" value of:
1.23.4.35
You can use string.LastIndexOf().
string input = "127.3.2.21.4";
int lastIndex = input.LastIndexOf('.');
string lastNumber = input.Substring(lastIndex + 1);
string increment = (int.Parse(lastNumber) + 1).ToString();
string result = string.Concat(input.Substring(0, lastIndex + 1), increment);
You need to extract more than just the last character. What if the last character is a 9 and then you add 1 to it? Then you need to correctly add one to the preceding character as well. For example, the string 5.29 should be processed to become 5.30 and not simply 5.210 or 5.20.
So I suggest you split the string into its number sections. Parse the last section into an integer. Increment it and then create the string again. I leave it as an exercise for the poster to actually write the few lines of code. Good practice!
Something like this:
var ip = "1.23.4.34";
var last = int.Parse(ip.Split(".".ToCharArray(),
StringSplitOptions.RemoveEmptyEntries).Last());
last = last + 1;
ip = string.Format("{0}.{1}",ip.Remove(ip.LastIndexOf(".")) , last);
If you are dealing with IP, there will be some extra code in case of .034, which should be 035 instead of 35. But that logic is not that complicated.
It's simple as this, use Split() and Join() String methods
String test = "1.23.4.34"; // test string
String[] splits = test.Split('.'); // split by .
splits[splits.Length - 1] = (int.Parse(splits[splits.Length - 1])+1).ToString(); // Increment last integer (Note : Assume all are integers)
String answ = String.Join(".",splits); // Use string join to make the string from string array. uses . separator
Console.WriteLine(answ); // Answer : 1.23.4.35
Using a bit of Linq
int[] int_arr = numberString.Split('.').Select(num => Convert.ToInt32(num)).ToArray();
int_arr[int_arr.Length - 1]++;
numberString = "";
for(int i = 0; i < int_arr.Length; i++) {
if( i == int_arr.Length - 1) {
numberString += int_arr[i].ToString();
}
else {
numberString += (int_arr[i].ToString() + ".");
}
}
Note: on phone so can't test.
My Solution is:
private static string calcNextCode(string value, int index)
{
if (value is null) return "1";
if (value.Length == index + 1) return value + "1";
int lastNum;
int myIndex = value.Length - ++index;
char myValue = value[myIndex];
if (int.TryParse(myValue.ToString(), NumberStyles.Integer, null, out lastNum))
{
var aStringBuilder = new StringBuilder(value);
if (lastNum == 9)
{
lastNum = 0;
aStringBuilder.Remove(myIndex, 1);
aStringBuilder.Insert(myIndex, lastNum);
return calcNextCode(aStringBuilder.ToString(), index++);
}
else
{
lastNum++;
}
aStringBuilder.Remove(myIndex, 1);
aStringBuilder.Insert(myIndex, lastNum);
return aStringBuilder.ToString();
}
return calcNextCode(value, index++);
}
I want the program to get all of the elem1-elem7 info, add it together, and put it into the totalElem variable. That part works fine.
The part I'm stuck on, is that I want to take that number (lets say 30 for example), and put it on the end of a decimal to use it as a multiplier. Therefore 30 would become 1.30.
The error I'm getting is:
Cannot implicitly convert type 'string' to 'decimal'.
Please note, that is not where the variable definitions really are in the code. I just put them there so I didn't have to post my whole program.
private void calculateButton_Click(object sender, EventArgs e)
{
int startingSheetDPS;
int chd;
int skill;
int elem7;
int elem6;
int elem5;
int elem4;
int elem3;
int elem2;
int elem1;
int totalElem;
decimal elemMultiplier;
decimal baseMultiplier;
elem1 = Convert.ToInt32(ele1.Text);
elem2 = Convert.ToInt32(ele2.Text);
elem3 = Convert.ToInt32(ele3.Text);
elem4 = Convert.ToInt32(ele4.Text);
elem5 = Convert.ToInt32(ele5.Text);
elem6 = Convert.ToInt32(ele6.Text);
elem7 = Convert.ToInt32(ele7.Text);
chd = Convert.ToInt32(chd1.Text);
skill = Convert.ToInt32(skill1.Text);
totalElem = elem1 + elem2 + elem3 + elem4 + elem5 + elem6 + elem7;
elemMultiplier = 1 + "." + totalElem;
}
In short, I want to be able to turn elemMultiplier into a decimal variable, containing 1.totalElem.
Ok, a really dirty and fast way, replace your
elemMultiplier = 1 + "." + totalElem;
with
elemMultiplier = decimal.Parse("1." + totalElem);
Be ware, this is locale-dependant.
Use this:
String elemMul = "1." + totalElem.ToString();
elemMultiplier = Convert.ToDecimal(elemMul);
Your code shows problem because "." is a string which cannot be converted to decimal implicitly.
Don't concatenate strings. Just do the math:
elemMultiplier =
Convert.ToDecimal(1 + (totalElem / Math.Pow(10, totalElem.ToString().Length)));
(Edited after Gusman noticed a problem.)
When I run this through the debugger the result for string CL_S and string NA_S are the same value, which is 122.13.
Not sure why it does this since the indexOf is different - the second one does not exist.
text = "4R|1|^^^100^CL_S|122.13|38||||F|||20070628114638"
string str = text;
try
{
int a_first = str.IndexOf("^^^100") + "^^^100".Length + 1;
string str_a = str.Substring(a_first);
string[] words_a = str_a.Split('|');
string CL_S = words_a[1];
int b_first = str.IndexOf("^^^101") + "^^^101".Length + 1;
string str_b = str.Substring(b_first);
string[] words_b = str_b.Split('|');
string NA = words_b[1];
Step through a debugger and look at the values of the variables.
Here's a quick analysis which should help point you towards the problem:
a_first has the value 12
str_a has the value "CLS_S|122.13|..."
b_first has the value 6 (Note that you are adding -1 + 6 + 1; the -1 is from the IndexOf that doesn't have a match. IndexOf is working just fine.)
str_b has the value "^^100^CL_S|122.13|..."
When you split either str_a or str_b on a |, the second element (index [1]) of both will be 122.13.
In the second case the IndexOf call returns -1, and adding seven to that puts you at index 6.
When you use that in the Substring call you will get ^^100^ prefixed to the string, compared to the string from the first case.
As that doesn't contain any | characters, splitting will only give a different result for the first item in the array, and as you are getting the second item it will be the same as in the first case.
Run this on IDEONE https://ideone.com/F6KDNS
using System;
public class Test
{
public static void Main()
{
string str = "4R|1|^^^100^CL_S|122.13|38||||F|||20070628114638" ;
int a_first = str.IndexOf("^^^100") + "^^^100".Length + 1;
string str_a = str.Substring(a_first);
string[] words_a = str_a.Split('|');
string CL_S = words_a[1];
Console.WriteLine(a_first);
Console.WriteLine(str_a);
Console.WriteLine(CL_S);
Console.WriteLine();
int b_first = str.IndexOf("^^^101") + "^^^101".Length + 1;
string str_b = str.Substring(b_first);
string[] words_b = str_b.Split('|');
string NA = words_b[1];
Console.WriteLine(b_first);
Console.WriteLine(str_b);
Console.WriteLine(NA);
}
}
I got this:
12
CL_S|122.13|38||||F|||20070628114638
122.13
6
^^100^CL_S|122.13|38||||F|||20070628114638
122.13
So you can see that the second IndexOf returns -1 => b_first is 6. This means that you the two strings in both have their first break at
CL_S| & ^^100^CL_S|
And thus both have second item = 122.13
Is there any way available to give start and ending value to the string and string copy all that values in c#
e.g
My name is testing.
Now i want to copy 'name is'
from the string how i can achieve. I don't have any specific length of the string, It could be increase and decrease.
Try String.IndexOf and String.Substring.
String s1 = "My name is testing.";
String sub = "name is";
int index = s1.IndexOf(sub);
String found = s2.Substring(index, sub.Length);
Well, I'm not completely sure what you are asking here, but...
I don't have any specific length of the string
Sure you do.
string s = "name is";
int len = s.Length; // len == 7
To concatenate strings you can use the + operator.
string prefix = "prefix : "
string suffix = "suffix : "
string s = prefix + "name is" + suffix;
int len = s.Length; // len == 25
I think I nailed your requirement and the solution. Do let me know if this is what you wanted and if this works!
MessageBox.Show(FindStringBetween("My name is farhan.", "My", "is"));
public string FindStringBetween(string SourceString, string StartString, string EndString)
{
int StartSelection = StartString.Length;
int EndSelection = SourceString.IndexOf(EndString)+EndString.Length;
return (SourceString.Substring(StartSelection).Substring(0, EndSelection-StartSelection));
}