I'm tring to remove the char '.' from a string except the last occurrence; for example the string
12.34.56.78
should became
123456.78
I'm using this loop:
while (value != null && value.Count(c => c == '.') > 1)
{
value = value.Substring(0, value.IndexOf('.')) + value.Substring(value.IndexOf('.') + 1);
}
I wonder if there is a cleaner way (maybe using linq?) to do this whitout an explicit loop?
(I know there is a very similar question but is about perl and things are quite different)
int lastIndex = value.LastIndexOf('.');
if (lastIndex > 0)
{
value = value.Substring(0, lastIndex).Replace(".", "")
+ value.Substring(lastIndex);
}
Perhaps a mixture of string methods and Linq:
string str = "12.34.56.78";
Char replaceChar = '.';
int lastIndex = str.LastIndexOf(replaceChar);
if (lastIndex != -1)
{
IEnumerable<Char> chars = str
.Where((c, i) => c != replaceChar || i == lastIndex);
str = new string(chars.ToArray());
}
Demo
I would do that way:
search for the last '.' ;
substring [0 .. indexOfLastDot] ;
remove in place any '.' of the substring
concatenate the substring with the rest of the original string, [indexOfLastDot .. remaining]
OR
search for the last '.'
for each enumerated char of the string
if it’s a '.' and i ≠ indexOfLastDot, remove it
var splitResult = v.Split(new char[] { '.' }).ToList();
var lastSplit = splitResult.Last();
splitResult.RemoveAt(splitResult.Count - 1);
var output = string.Join("", splitResult) + "." + lastSplit;
I would do it that way. The neatest way isn't always the shortest way.
Something like this should do the trick. Whether it is "good" or not is another matter. Note also that there is no error checking. Might want to check for null or empty string and that the string has at least one "." in it.
string numbers = "12.34.56.78";
var parts = String.Split(new char [] {'.'});
string newNumbers = String.Join("",parts.Take(parts.Length-1)
.Concat(".")
.Concat(parts.Last());
I don't claim that this would have great performance characteristics for long strings, but it does use Linq ;-)
you do not have to use loop:
//string val = "12345678";
string val = "12.34.56.78";
string ret = val;
int index = val.LastIndexOf(".");
if (index >= 0)
{
ret = val.Substring(0, index).Replace(".", "") + val.Substring(index);
}
Debug.WriteLine(ret);
Related
I have a string like AX_1234X_12345_X_CXY, I want to remove X from after the first underscore _ i.e. from 1234X to 1234. So final output will be like AX_1234_12345_X_CXY. How to do it?? If I use .Replace("X", "") it will replace all X which I don't want
You can iterate trough the string from the first occurrence of '_' .
you can find the first occurrence of '_' using IndexOf().
when loop will get to 'X' it will not append it to the "fixed string".
private static void Func()
{
string Original = "AX_1234X_12345_X_CXY";
string Fixed = Original.Substring(0, Original.IndexOf("_", 0));
// in case you want to remove all 'X`s' after first occurrence of `'_'`
// just dont use that variable
bool found = false;
for (int i = Original.IndexOf("_", 0); i < Original.Length; i++)
{
if (Original[i].ToString()=="X" && found == false)
{
found = true;
}
else
{
Fixed += Original[i];
}
}
Console.WriteLine(Fixed);
Console.ReadLine();
}
Why not good old IndexOf and Substring?
string s = "AX_1234X_12345_X_CXY";
int pUnder = s.IndexOf('_');
if (pUnder >= 0) { // we have underscope...
int pX = s.IndexOf('X', pUnder + 1); // we should search for X after the underscope
if (pX >= 0) // ...as well as X after the underscope
s = s.Substring(0, pX) + s.Substring(pX + 1);
}
Console.Write(s);
Outcome:
AX_1234_12345_X_CXY
string original = #"AX_1234X_12345_X_CXY";
original = #"AX_1234_12345_X_CXY";
One way is String.Remove, because you can tell exactly where to remove from. If the offending "X" is always in the same place, you can use:
string newString = old.Remove(7,1);
This will remove 1 character starting as position 7 (counting from zero as the beginning of the string).
If not always in the same character position, you might try:
int xPos = old.IndexOf("X");
string newString = old.Remove(xPos,1);
EDIT:
Based on OP comment, the "X" we're targeting occurs just after the first underscore character, so let's index off of the first underscore:
int iPosUnderscore = old.IndexOf("_");
string newString = old.Remove(iPosUnderscore + 1 ,1); // start after the underscore
Try looking at string.IndexOf or string.IndexOfAny
string s = "AX_1234X_12345_X_CXY";
string ns = HappyChap(s);
public string HappyChap(string value)
{
int start = value.IndexOf("X_");
int next = start;
next = value.IndexOf("X_", start + 1);
if (next > 0)
{
value = value.Remove(next, 1);
}
return value;
}
If and only if this is always the format then it should be a simple matter of combining substrings of the original text without including the x in that position. But the op hasn't stated that this is always the case. So if this is always the format and the same character position is always removed then you could simply just
string s = "AX_1234X_12345_X_CXY";
string newstring = s.Substring(0, 7) + s.Substring(8);
OK, based on only the second set of numbers being variable in length, you could then do something like:
int startpos = s.IndexOf('_', 4);
string newstring = s.Substring(0, startpos - 1) + s.Substring(startpos);
with this code, the following tests resulted in:
"AX_1234X_12345_X_CXY" became "AX_1234_12345_X_CXY"
"AX_123X_12345_X_CXY" became "AX_123_12345_X_CXY"
"AX_234X_12345_X_CXY" became "AX_234_12345_X_CXY"
"AX_1X_12345_X_CXY" became "AX_1_12345_X_CXY"
Something like this could work. I'm sure there's a more elegant solution.
string input1 = "AX_1234X_12345_X_CXY";
string pattern1 = "^[A-Z]{1,2}_[0-9]{1,4}(X)";
string newInput = string.Empty;
Match match = Regex.Match(input1, pattern1);
if(match.Success){
newInput = input1.Remove(match.Groups[1].Index, 1);
}
Console.WriteLine(newInput);
i feel dumb for asking a most likely silly question.
I am helping someone getting the results he wishes for his custom compiler that reads all lines of an xml file in one string so it will look like below, and since he wants it to "Support" to call variables inside the array worst case scenario would look like below:
"Var1 = [5,4,3,2]; Var2 = [2,8,6,Var1;4];"
What i need is to find the first ";" after "[" and "]" and split it, so i stand with this:
"Var1 = [5,4,3,2];
It will also have to support multiple "[", "]" for example:
"Var2 = [5,Var1,[4],2];"
EDIT: There may also be Data in between the last "]" and ";"
For example:
"Var2 = [5,[4],2]Var1;
What can i do here? Im kind of stuck.
You can try regular expressions, e.g.
string source = "Var1 = [5,4,3,2]; Var2 = [2,8,6,Var1;4];";
// 1. final (or the only) chunk doesn't necessary contain '];':
// "abc" -> "abc"
// 2. chunk has at least one symbol except '];'
string pattern = ".+?(][a-zA-Z0-9]*;|$)";
var items = Regex
.Matches(source, pattern)
.OfType<Match>()
.Select(match => match.Value)
.ToArray();
Console.Write(string.Join(Environment.NewLine, items));
Outcome:
Var1 = [5,4,3,2]abc123;
Var2 = [2,8,6,Var1;4];
^([^;]+);
This regex should work for all.
You can use it like here:
string[] lines =
{
"Var1 = [5,4,3,2]; Var2 = [2,8,6,Var1;4];",
"Var2 = [5,[4],2]Var1; Var2 = [2,8,6,Var1;4];"
};
Regex pattern = new Regex(#"^([^;]+);");
foreach (string s in lines){
Match match = pattern.Match(s);
if (match.Success)
{
Console.WriteLine(match.Value);
}
}
The explanation is:
^ means starts with and is [^;] anything but a semicolon
+ means repeated one or more times and is ; followed by a semicolon
This will find Var1 = [5,4,3,2]; as well as Var1 = [5,4,3,2];
You can see the output HERE
public static string Extract(string str, char splitOn)
{
var split = false;
var count = 0;
var bracketCount = 0;
foreach (char c in str)
{
count++;
if (split && c == splitOn)
return str.SubString(0, count);
if (c == '[')
{
bracketCount++;
split = false;
}
else if (c == ']')
{
bracketCount--;
if (bracketCount == 0)
{
split = true;
}
else if (bracketCount < 0)
throw new FormatException(); //?
}
}
return str;
}
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());
Problem: spending too much time solving simple problems. Oh, here's the simple problem.
Input: string inStr, char delimiter
Output: string[] outStrs where string.Join("", outStrs) == inStr and each item in outStrs before the last item must end with the delimiter. If inStr ends with the delimiter, then the last item in outStrs ends with the delimiter as well.
Example 1:
Input: "my,string,separated,by,commas", ','
Output: ["my,", "string,", "separated,", "by,", "commas"]
Example 2:
Input: "my,string,separated,by,commas,", ','
Output: ["my,", "string,", "separated,", "by,", "commas,"] (notice trailing comma)
Solution with Regex: here
I want to avoid using Regex, simply because this requires only character comparison. It's algorithmically just as complex to do as what string.Split() does. It bothers me that I cannot find a more succinct way to do what I want.
My bad solution, which doesn't work for me... it should be faster and more succinct.
var outStr = inStr.Split(new[]{delimiter},
StringSplitOptions.RemoveEmptyEntries)
.Select(x => x + delimiter).ToArray();
if (inStr.Last() != delimiter) {
var lastOutStr = outStr.Last();
outStr[outStr.Length-1] = lastOutStr.Substring(0, lastOutStr.Length-1);
}
Using LINQ:
string input = "my,string,separated,by,commas";
string[] groups = input.Split(',');
string[] output = groups
.Select((x, idx) => x + (idx < groups.Length - 1 ? "," : string.Empty))
.Where(x => x != "")
.ToArray();
Split the string into groups, then transform every group that is not the last element by appending a comma to it.
Just thought of another way you could do it, but I don't think this method is as clear:
string[] output = (input + ',').Split( new[] { "," }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x + ',').ToArray();
Seems pretty simple to me without using Regex:
string inStr = "dasdasdas";
char delimiter = 'A';
string[] result = inStr.Split(new string[] { inStr }, System.StringSplitOptions.RemoveEmptyEntries);
string lastItem = result[result.Length - 1];
int amountOfLoops = lastItem[lastItem.Length - 1] == delimiter ? result.Length - 1 : result.Length - 2;
for (int i = 0; i < amountOfLoops; i++)
{
result[i] += delimiter;
}
public static IEnumerable<string> SplitAndKeep(this string s, string[] delims)
{
int start = 0, index;
string selectedSeperator = null;
while ((index = s.IndexOfAny(delims, start, out selectedSeperator)) != -1)
{
if (selectedSeperator == null)
continue;
if (index - start > 0)
yield return s.Substring(start, index - start);
yield return s.Substring(index, selectedSeperator.Length);
start = index + selectedSeperator.Length;
}
if (start < s.Length)
{
yield return s.Substring(start);
}
}
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++);
}