I was just wondering if there is a way of comparing c# strings with a startIndex for the first one. I have a long string and an index and want to find if the next characters are equal to a string. The only way I have found to do this is:
public static bool Equals (string longString, int index, string compare) => longString.Substring(index, compare.Length) == compare;
I think this is inefficient because you are unnecessarily creating a substring for each time you compare a new string at the index. Is there a more efficient way? I looked at string.Equals but it doesn't look like something I would be comfortable trying to rewrite.
string.Compare(longString, startIndex, compare, 0, compare.Length, isIgnoreCase) == 0;
Please see:
https://learn.microsoft.com/en-us/dotnet/api/system.string.compare
This is the best solution I have found.
public static bool Equals (string longString, int index, string compare)
{
if (longString.Length > (index + compare.Length))
return false;
for (int n = 0; n < compare.Length; n++)
{
if (longString[index + n] != compare[n])
return false;
}
return true;
}
IndexOf() contains an overload where we can set startIndex and check whether the string contains desired word, then we should check if the sub-string after the startIndex has the same length as the desired word and note that the following solution doesn't create a new sub-string at all:
var startIndex = 2;
var longString = "56789";
var wordToFind = "789";
var isEqual = longString.IndexOf(wordToFind, startIndex) != -1 && wordToFind.Length == (longString.Length - startIndex);
Console.WriteLine(isEqual);
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 need to capitalize everything before the second - from the beginning of the string in .NET. What is the best way to do this? The string before the second dash can be anything. I need a new single string once this is complete.
Before
Tt-Fga - Louisville - Kentucky
After
TT-FGA - Louisville - Kentucky
This should get the job done for your specific case:
public static string ToUpperUntilSecondHyphen(string text)
{
int index = text.IndexOf('-', text.IndexOf('-') + 1);
return text.Substring(0, index).ToUpper() + text.Substring(index);
}
A more generalized method could look something like this:
public static string ToUpperUntilNthOccurrenceOfChar(string text, char c, int occurrences)
{
if (occurrences > text.Count(x => x == c))
{
return text.ToUpper();
}
int index = 0;
for (int i = 0; i < occurrences; i++, index++)
{
index = text.IndexOf(c, index);
}
return text.Substring(0, index).ToUpper() + text.Substring(index);
}
Identify the location of the hyphen with IndexOf. You'll have to use this function twice so that you can find the first hyphen, and then the second one.
Construct the substring that only contains the characters up to that with Substring. Construct the substring that contains all the remaining characters as well.
Upper case the first string with ToUpper.
Concatenate with the + operator.
(.*?-.*)(?=-)
You can use replace here.Replace with $1.upper() or something which is available in c#.
See
http://regex101.com/r/yR3mM3/50
I went ahead and did this. If there is a better answer let me know.
var parts = #event.EventParent.Name.Split(new[] {'-'}, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < parts.Length; i++)
{
if (i >= 2)
break;
parts[i] = parts[i].ToUpper();
}
#event.EventParent.Name = string.Join("-", parts);
I asked this question yesterday but it wasn't well received mainly due to how I asked it so ill try do better this time.
I have a string variable called message. lets say message equals "ABCDABCDABCDABCD"
now I need to do some processing on the characters in the string but not all at the same time, I want to access characters [0][4][8][12] on the first pass of the function, put each of these characters in a string and return it which is easy done if I pass an integer to my function lets say 4 and with in a for loop do
if(i % int == 0)
{
string += message[i];
}
this should return "AAAA"
the next time I call the function ill need elements [0][1], [4][5], [8][9], [12][13] and the time after that ill need [0][1][2], [4][5][6], [8][9][10], [12][13][14].
I need the characters returned in a string in the order they were taken, I could do this by changing my int I pass the function but then id need to call the function several times and do work on the returned strings to get them into the order they were taken, which I have already tried and it slowed my program down when dealing with large messages > 10k characters.
Please don't delete or put my question on hold, im quite happy to give more information on my problem if its not clear, ill seldom post to this site and usually try and find a solution myself, there are too many acceptance junkies on here for my liking. but I would appreciate some help from some of them regarding this.Thanks
Edit
I understand its not easy to figure it out and I have to say im not the best at describing it, its a vigenere cracker in WPF, I have done the kasiski examination on a piece of text and graphed out all the data, it finds the key length 90% of the time or gives me the best clue to what the key might be, now im calculating the frequency of bi,tri and quad grams of the message based on the data from the kasiski exam, lets say the key is 5 and the message is "ABCDABCDABCDABCD" im calculating probability on only the characters of the key Im changing so when I try key AAAAA im only wanting to calculate monograms on elements [0][4][9][14] of the message, ill run through 26 characters up to ZAAAA and take the most probable then I move onto element [1] of the key, lets say FAAAA gave the best score on the first element of the key. now I need elements [0][1],[5][6],[9][10][13][14] as im calculating probability on 2 pieces on the key FCAAA, so the length of the key and what key character im working on will determine what elements of the message ill be taking.
One-liner with LINQ (I use Batch extension from MoreLINQ, but you can use your own) which selects all required chars from input string:
string message = "ABCDABCDABCDABCD";
int size = 4;
int charsToTake = 2;
var characters = message.Batch(size).SelectMany(b => b.Take(charsToTake));
If you need result as string, you can easily create one:
var result = new String(characters.ToArray());
// ABABABAB
More efficient way - create your own method which will split string by substrings of required length:
public static IEnumerable<string> ToSubstrings(this string s, int length)
{
int index = 0;
while (index + length < s.Length)
{
yield return s.Substring(index, length);
index += length;
}
if (index < s.Length)
yield return s.Substring(index);
}
I would also create method for safe getting substring from start of string (to avoid annoying string length check and passing zero as start index):
public static string SubstringFromStart(this string s, int length)
{
return s.Substring(0, Math.Min(s.Length, length));
}
Now its very clear what you are doing:
var substrings = message.ToSubstrings(size)
.Select(s => s.SubstringFromStart(charsToTake));
var result = String.Concat(substrings);
Here is a simple program which does what you want, if I understand correctly:
static void Main(string[] args)
{
string data = "ABCDABCDABCDABCD";
Console.WriteLine(StrangeSubstring(data,4, 1));
// "AAAA"
Console.WriteLine(StrangeSubstring(data,4, 2));
// "ABABABAB"
Console.WriteLine(StrangeSubstring(data,4, 3));
// "ABCABCABCABC"
}
static string StrangeSubstring(string input, int modulo, int length)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < input.Length; ++i)
{
if (i % modulo == 0)
{
for (int j = 0; j<length; ++j)
{
if (i+j < input.Length)
sb.Append(input[i+j]);
}
}
}
return sb.ToString();
}
My solution will be like this
static string MethodName(int range){
StringBuilder sb = new StringBuilder();
for(int i = 0 ; i < str.Length ; i++){
if(i % 4 == 0){
sb.Append(str[i]);
for(int j = i + 1 ; j <= i + range ; j ++){
if(j >= str.Length)
break;
sb.Append(str[j]);
}
}
}
return sb.ToString();
}
you can parse your string to a char array :
string message="ABCDABCDABCDABCD";
char[] myCharArray = message.ToCharArray();
string result="";
for(int i=0, i<myCharArray.Length -1 ; i++)
{
if(i%4 ==0)
result+=myCharArray[i];
}
EDIT 1 :
public string[] myfunction(char[] charArray)
{
List<string> result = new List<string>();
for(int i=0, i<charArray.length -1; i=i+4)
{
result.add(charArray[i]+charArray[i+1])
}
return result.toArray();
}
This is a recursive solution. In YourFunction, PatternLength is the length of the character pattern which is repeated (so, 4 for "ABCD"), Offset is where you start in the pattern (e.g. 0 if you start with "A") and SubstringLength is the number of characters.
The function call in Main will give you all "A". If you change SubstringLength to 2, it gives you all "AB". There is no error handling, make sure then PatternLength<=Offest+SubstringLength
namespace Foo
{
class Bar
{
static void Main(string[] args)
{
Console.WriteLine(YourFunction("ABCABCABCABCABCABCABC", 3, 0,1));
Console.ReadKey();
}
static string YourFunction(string SubString, int PatternLength, int Offset, int SubstringLength)
{
string result;
if (SubString.Length <= PatternLength)
{
result = SubString.Substring(Offset, SubstringLength);
}
else
{
result = YourFunction(SubString.Substring(PatternLength, (SubString.Length - PatternLength)), PatternLength, Offset, SubstringLength) + SubString.Substring(Offset, SubstringLength);
}
return result;
}
}
}
I'd like to find a specific last character in a StringBuilder.
I know, I can solve it with while() but is there an build it option to do that easily?
eg:
private static StringBuilder mySb = new StringBuilder("");
mySb.Add("This is a test[n] I like Orange juice[n] Can you give me some?");
Now: It shoud find the ] and give me the possition. Like: 40
Thanks in advance
Since there is no builtin method and always creating a string from the StringBuilder via ToString can be quite inefficient you could create an extension method for this purpose:
public static int LastIndexOf(this StringBuilder sb, char find, bool ignoreCase = false, int startIndex = -1, CultureInfo culture = null)
{
if (sb == null) throw new ArgumentNullException(nameof(sb));
if (startIndex == -1) startIndex = sb.Length - 1;
if (startIndex < 0 || startIndex >= sb.Length) throw new ArgumentException("startIndex must be between 0 and sb.Lengh-1", nameof(sb));
if (culture == null) culture = CultureInfo.InvariantCulture;
int lastIndex = -1;
if (ignoreCase) find = Char.ToUpper(find, culture);
for (int i = startIndex; i >= 0; i--)
{
char c = ignoreCase ? Char.ToUpper(sb[i], culture) : (sb[i]);
if (find == c)
{
lastIndex = i;
break;
}
}
return lastIndex;
}
Add it to a static, accessible (extension) class, then you can use it in this way:
StringBuilder mySb = new StringBuilder("");
mySb.Append("This is a test[n] I like Orange juice[n] Can you give me some?");
int lastIndex = mySb.LastIndexOf(']'); // 39
Convert the StringBuilder to a string with the toString method, thereafter you can make use of the LastIndexOf method.
mySb.ToString().LastIndexOf(']');
LastIndexOf:
Reports the zero-based index position of the last occurrence of a
specified Unicode character or string within this instance. The method
returns -1 if the character or string is not found in this instance.
This member is overloaded. For complete information about this member,
including syntax, usage, and examples, click a name in the overload
list.
My question is pretty straight forward, how can I find all the indices of a string inside of another string? This is the code I wrote but the problem is that all it does is return the exact same index multiple times. Here it is:
public static int[] IndicesOf(this string s, string Search, int StartIndex)
{
List<int> indices = new List<int>();
int lastIndex = 0;
lastIndex = s.IndexOf(Search);
while (lastIndex != -1)
{
indices.Add(lastIndex);
lastIndex = s.IndexOf(Search, lastIndex);
}
return indices.ToArray();
}
I don't know what is wrong with this code. I think I may need to advance the index before the next search.
My guess is that you should add 1 to your second s.IndexOf call.
That is:
lastIndex = s.IndexOf(Search, lastIndex + 1);