Mutable String Editing in C# / .NET - c#

I want to take and edit a string in-place in a .NET app. I know that StringBuilder allows me to do in-place appends, inserts, and replaces, but it does not allow an easy way of doing stuff like this:
while (script.IndexOf("#Unique", StringComparison.InvariantCultureIgnoreCase) != -1)
{
int Location = script.IndexOf("#Unique", StringComparison.InvariantCultureIgnoreCase);
script = script.Remove(Location, 7);
script = script.Insert(Location, Guid.NewGuid().ToString());
}
As there is no IndexOf in StringBuilder. Does anyone have an effective way to do in-place editing of textual information?
Edit #1:
Changed sample to make more obvious that each 'replace' needs to have a different result.

If your code really is this straightforward then why not just use one of the built-in Replace methods, either on string, StringBuilder or Regex?
EDIT FOLLOWING COMMENT...
You can replace each occurrence with a separate value by using one of the overloads of Regex.Replace that takes a MatchEvaluator argument:
string foo = "blah blah #Unique blah #Unique blah blah #Unique blah";
// replace each occurrence of "#Unique" with a separate guid
string bar = Regex.Replace(foo, "#Unique",
new MatchEvaluator(m => Guid.NewGuid().ToString()),
RegexOptions.IgnoreCase));

How many replacements will you be doing?
If its not four figures, then just accept the new string instances, you may be prematurely optimising...
Another solution... Split on "#uniqueID" then rejoin with a StringBuilder adding your seperator for each iteration.

How about StringBuilder "Replace" method:
StringBuilder script;
script.Replace("#Unique", GetGuidString());

StringBuilder is made so that you can easily add to it, but at the tradeoff that it's difficult to search in it - and especially, it's more difficult (i.e. slower) to index it.
If you need to modify some characters "in-place", it's best to do it on the resulting string.
But it's difficult to know from your question what is the right answer for you, my feeling is that you shouldn't be needing in-place replacement in a StringBuilder, and the problem is somewhere else/you do something else wrong.

User Dennis has provided an IndexOf extension method for StringBuilder. With this, you should be able to use StringBuilder in this manner.

Can you use a string split to do this efficiently?
Something like:
var sections = "a-#Unique-b-#Unique-c".Split(new string[] { "#Unique" }, StringSplitOptions.None);
int i;
StringBuilder builder = new StringBuilder();
for(i = 0; i < sections.Length - 1; i++)
{
builder.Append(sections[i]);
builder.Append(Guid.NewGuid().ToString());
}
builder.Append(sections[i]);
Console.WriteLine(builder.ToString());
Console.ReadKey(true);

complex but should be performant solution
public StringBuilder Replace(this StringBuilder sb, string toReplace, Func<string> getReplacement)
{
for (int i = 0; i < sb.Length; i++)
{
bool replacementFound = true;
for (int toReplaceIndex = 0; toReplaceIndex < toReplace.Length; toReplaceIndex++)
{
int sbIndex = toReplaceIndex + i;
if (sbIndex < sb.Length)
{
return sb;
}
if (sb[sbIndex] != toReplace[toReplaceIndex])
{
replacementFound = false;
break;
}
}
if (replacementFound)
{
string replacement = getReplacement();
// reuse the space of the toReplace string
for (int replacementIndex = 0; replacementIndex < toReplace.Length && replacementIndex < replacement.Length; replacementIndex++)
{
int sbIndex = replacementIndex + i;
sb[sbIndex] = replacement[i];
}
// remove toReplace string remainders
if (replacement.Length < toReplace.Length)
{
sb.Remove(i + replacement.Length, replacement.Length - toReplace.Length)
}
// insert chars not yet inserted
if (replacement.Length > toReplace.Length)
{
sb.Insert(i + toReplace.Length, replacement.ToCharArray(toReplace.Length, toReplace.Length - replacement.Length));
}
}
}
return sb;
}
use case
var sb = new StringBuilder(script);
script = sb.Replace("#Unique", () => Guid.NewGuid().ToString()).ToString();

You are going to need to use an unmanaged code block
As simple as declare a pointer to your string and manipulate it in memory.
Example
unsafe
{
char* ip;
ip = &to_your_string;
}

Related

Convert byte array of zeros and ones (0,1) to string of zeros and ones [duplicate]

What's the most efficient way to concatenate strings?
Rico Mariani, the .NET Performance guru, had an article on this very subject. It's not as simple as one might suspect. The basic advice is this:
If your pattern looks like:
x = f1(...) + f2(...) + f3(...) + f4(...)
that's one concat and it's zippy, StringBuilder probably won't help.
If your pattern looks like:
if (...) x += f1(...)
if (...) x += f2(...)
if (...) x += f3(...)
if (...) x += f4(...)
then you probably want StringBuilder.
Yet another article to support this claim comes from Eric Lippert where he describes the optimizations performed on one line + concatenations in a detailed manner.
The StringBuilder.Append() method is much better than using the + operator. But I've found that, when executing 1000 concatenations or less, String.Join() is even more efficient than StringBuilder.
StringBuilder sb = new StringBuilder();
sb.Append(someString);
The only problem with String.Join is that you have to concatenate the strings with a common delimiter.
Edit: as #ryanversaw pointed out, you can make the delimiter string.Empty.
string key = String.Join("_", new String[]
{ "Customers_Contacts", customerID, database, SessionID });
There are 6 types of string concatenations:
Using the plus (+) symbol.
Using string.Concat().
Using string.Join().
Using string.Format().
Using string.Append().
Using StringBuilder.
In an experiment, it has been proved that string.Concat() is the best way to approach if the words are less than 1000(approximately) and if the words are more than 1000 then StringBuilder should be used.
For more information, check this site.
string.Join() vs string.Concat()
The string.Concat method here is equivalent to the string.Join method invocation with an empty separator. Appending an empty string is fast, but not doing so is even faster, so the string.Concat method would be superior here.
From Chinh Do - StringBuilder is not always faster:
Rules of Thumb
When concatenating three dynamic string values or less, use traditional string concatenation.
When concatenating more than three dynamic string values, use StringBuilder.
When building a big string from several string literals, use either the # string literal or the inline + operator.
Most of the time StringBuilder is your best bet, but there are cases as shown in that post that you should at least think about each situation.
If you're operating in a loop, StringBuilder is probably the way to go; it saves you the overhead of creating new strings regularly. In code that'll only run once, though, String.Concat is probably fine.
However, Rico Mariani (.NET optimization guru) made up a quiz in which he stated at the end that, in most cases, he recommends String.Format.
Here is the fastest method I've evolved over a decade for my large-scale NLP app. I have variations for IEnumerable<T> and other input types, with and without separators of different types (Char, String), but here I show the simple case of concatenating all strings in an array into a single string, with no separator. Latest version here is developed and unit-tested on C# 7 and .NET 4.7.
There are two keys to higher performance; the first is to pre-compute the exact total size required. This step is trivial when the input is an array as shown here. For handling IEnumerable<T> instead, it is worth first gathering the strings into a temporary array for computing that total (The array is required to avoid calling ToString() more than once per element since technically, given the possibility of side-effects, doing so could change the expected semantics of a 'string join' operation).
Next, given the total allocation size of the final string, the biggest boost in performance is gained by building the result string in-place. Doing this requires the (perhaps controversial) technique of temporarily suspending the immutability of a new String which is initially allocated full of zeros. Any such controversy aside, however...
...note that this is the only bulk-concatenation solution on this page which entirely avoids an extra round of allocation and copying by the String constructor.
Complete code:
/// <summary>
/// Concatenate the strings in 'rg', none of which may be null, into a single String.
/// </summary>
public static unsafe String StringJoin(this String[] rg)
{
int i;
if (rg == null || (i = rg.Length) == 0)
return String.Empty;
if (i == 1)
return rg[0];
String s, t;
int cch = 0;
do
cch += rg[--i].Length;
while (i > 0);
if (cch == 0)
return String.Empty;
i = rg.Length;
fixed (Char* _p = (s = new String(default(Char), cch)))
{
Char* pDst = _p + cch;
do
if ((t = rg[--i]).Length > 0)
fixed (Char* pSrc = t)
memcpy(pDst -= t.Length, pSrc, (UIntPtr)(t.Length << 1));
while (pDst > _p);
}
return s;
}
[DllImport("MSVCR120_CLR0400", CallingConvention = CallingConvention.Cdecl)]
static extern unsafe void* memcpy(void* dest, void* src, UIntPtr cb);
I should mention that this code has a slight modification from what I use myself. In the original, I call the cpblk IL instruction from C# to do the actual copying. For simplicity and portability in the code here, I replaced that with P/Invoke memcpy instead, as you can see. For highest performance on x64 (but maybe not x86) you may want to use the cpblk method instead.
From this MSDN article:
There is some overhead associated with
creating a StringBuilder object, both
in time and memory. On a machine with
fast memory, a StringBuilder becomes
worthwhile if you're doing about five
operations. As a rule of thumb, I
would say 10 or more string operations
is a justification for the overhead on
any machine, even a slower one.
So if you trust MSDN go with StringBuilder if you have to do more than 10 strings operations/concatenations - otherwise simple string concat with '+' is fine.
Try this 2 pieces of code and you will find the solution.
static void Main(string[] args)
{
StringBuilder s = new StringBuilder();
for (int i = 0; i < 10000000; i++)
{
s.Append( i.ToString());
}
Console.Write("End");
Console.Read();
}
Vs
static void Main(string[] args)
{
string s = "";
for (int i = 0; i < 10000000; i++)
{
s += i.ToString();
}
Console.Write("End");
Console.Read();
}
You will find that 1st code will end really quick and the memory will be in a good amount.
The second code maybe the memory will be ok, but it will take longer... much longer.
So if you have an application for a lot of users and you need speed, use the 1st. If you have an app for a short term one user app, maybe you can use both or the 2nd will be more "natural" for developers.
Cheers.
It's also important to point it out that you should use the + operator if you are concatenating string literals.
When you concatenate string literals or string constants by using the + operator, the compiler creates a single string. No run time concatenation occurs.
How to: Concatenate Multiple Strings (C# Programming Guide)
Adding to the other answers, please keep in mind that StringBuilder can be told an initial amount of memory to allocate.
The capacity parameter defines the maximum number of characters that can be stored in the memory allocated by the current instance. Its value is assigned to the Capacity property. If the number of characters to be stored in the current instance exceeds this capacity value, the StringBuilder object allocates additional memory to store them.
If capacity is zero, the implementation-specific default capacity is used.
Repeatedly appending to a StringBuilder that hasn't been pre-allocated can result in a lot of unnecessary allocations just like repeatedly concatenating regular strings.
If you know how long the final string will be, can trivially calculate it, or can make an educated guess about the common case (allocating too much isn't necessarily a bad thing), you should be providing this information to the constructor or the Capacity property. Especially when running performance tests to compare StringBuilder with other methods like String.Concat, which do the same thing internally. Any test you see online which doesn't include StringBuilder pre-allocation in its comparisons is wrong.
If you can't make any kind of guess about the size, you're probably writing a utility function which should have its own optional argument for controlling pre-allocation.
Following may be one more alternate solution to concatenate multiple strings.
String str1 = "sometext";
string str2 = "some other text";
string afterConcate = $"{str1}{str2}";
string interpolation
Another solution:
inside the loop, use List instead of string.
List<string> lst= new List<string>();
for(int i=0; i<100000; i++){
...........
lst.Add(...);
}
return String.Join("", lst.ToArray());;
it is very very fast.
The most efficient is to use StringBuilder, like so:
StringBuilder sb = new StringBuilder();
sb.Append("string1");
sb.Append("string2");
...etc...
String strResult = sb.ToString();
#jonezy: String.Concat is fine if you have a couple of small things. But if you're concatenating megabytes of data, your program will likely tank.
System.String is immutable. When we modify the value of a string variable then a new memory is allocated to the new value and the previous memory allocation released. System.StringBuilder was designed to have concept of a mutable string where a variety of operations can be performed without allocation separate memory location for the modified string.
I've tested all the methods in this page and at the end I've developed my solution that is the fastest and less memory expensive.
Note: tested in Framework 4.8
[MemoryDiagnoser]
public class StringConcatSimple
{
private string
title = "Mr.", firstName = "David", middleName = "Patrick", lastName = "Callan";
[Benchmark]
public string FastConcat()
{
return FastConcat(
title, " ",
firstName, " ",
middleName, " ",
lastName);
}
[Benchmark]
public string StringBuilder()
{
var stringBuilder =
new StringBuilder();
return stringBuilder
.Append(title).Append(' ')
.Append(firstName).Append(' ')
.Append(middleName).Append(' ')
.Append(lastName).ToString();
}
[Benchmark]
public string StringBuilderExact24()
{
var stringBuilder =
new StringBuilder(24);
return stringBuilder
.Append(title).Append(' ')
.Append(firstName).Append(' ')
.Append(middleName).Append(' ')
.Append(lastName).ToString();
}
[Benchmark]
public string StringBuilderEstimate100()
{
var stringBuilder =
new StringBuilder(100);
return stringBuilder
.Append(title).Append(' ')
.Append(firstName).Append(' ')
.Append(middleName).Append(' ')
.Append(lastName).ToString();
}
[Benchmark]
public string StringPlus()
{
return title + ' ' + firstName + ' ' +
middleName + ' ' + lastName;
}
[Benchmark]
public string StringFormat()
{
return string.Format("{0} {1} {2} {3}",
title, firstName, middleName, lastName);
}
[Benchmark]
public string StringInterpolation()
{
return
$"{title} {firstName} {middleName} {lastName}";
}
[Benchmark]
public string StringJoin()
{
return string.Join(" ", title, firstName,
middleName, lastName);
}
[Benchmark]
public string StringConcat()
{
return string.
Concat(new String[]
{ title, " ", firstName, " ",
middleName, " ", lastName });
}
}
Yes, it use unsafe
public static unsafe string FastConcat(string str1, string str2, string str3, string str4, string str5, string str6, string str7)
{
var capacity = 0;
var str1Length = 0;
var str2Length = 0;
var str3Length = 0;
var str4Length = 0;
var str5Length = 0;
var str6Length = 0;
var str7Length = 0;
if (str1 != null)
{
str1Length = str1.Length;
capacity = str1Length;
}
if (str2 != null)
{
str2Length = str2.Length;
capacity += str2Length;
}
if (str3 != null)
{
str3Length = str3.Length;
capacity += str3Length;
}
if (str4 != null)
{
str4Length = str4.Length;
capacity += str4Length;
}
if (str5 != null)
{
str5Length = str5.Length;
capacity += str5Length;
}
if (str6 != null)
{
str6Length = str6.Length;
capacity += str6Length;
}
if (str7 != null)
{
str7Length = str7.Length;
capacity += str7Length;
}
string result = new string(' ', capacity);
fixed (char* dest = result)
{
var x = dest;
if (str1Length > 0)
{
fixed (char* src = str1)
{
Unsafe.CopyBlock(x, src, (uint)str1Length * 2);
x += str1Length;
}
}
if (str2Length > 0)
{
fixed (char* src = str2)
{
Unsafe.CopyBlock(x, src, (uint)str2Length * 2);
x += str2Length;
}
}
if (str3Length > 0)
{
fixed (char* src = str3)
{
Unsafe.CopyBlock(x, src, (uint)str3Length * 2);
x += str3Length;
}
}
if (str4Length > 0)
{
fixed (char* src = str4)
{
Unsafe.CopyBlock(x, src, (uint)str4Length * 2);
x += str4Length;
}
}
if (str5Length > 0)
{
fixed (char* src = str5)
{
Unsafe.CopyBlock(x, src, (uint)str5Length * 2);
x += str5Length;
}
}
if (str6Length > 0)
{
fixed (char* src = str6)
{
Unsafe.CopyBlock(x, src, (uint)str6Length * 2);
x += str6Length;
}
}
if (str7Length > 0)
{
fixed (char* src = str7)
{
Unsafe.CopyBlock(x, src, (uint)str7Length * 2);
}
}
}
return result;
}
You can edit the method and adapt it to your case. For example you can make it something like
public static unsafe string FastConcat(string str1, string str2, string str3 = null, string str4 = null, string str5 = null, string str6 = null, string str7 = null)
For just two strings, you definitely do not want to use StringBuilder. There is some threshold above which the StringBuilder overhead is less than the overhead of allocating multiple strings.
So, for more that 2-3 strings, use DannySmurf's code. Otherwise, just use the + operator.
It really depends on your usage pattern.
A detailed benchmark between string.Join, string,Concat and string.Format can be found here: String.Format Isn't Suitable for Intensive Logging
(This is actually the same answer I gave to this question)
It would depend on the code.
StringBuilder is more efficient generally, but if you're only concatenating a few strings and doing it all in one line, code optimizations will likely take care of it for you. It's important to think about how the code looks too: for larger sets StringBuilder will make it easier to read, for small ones StringBuilder will just add needless clutter.

How to reverse string in C# [duplicate]

I didn't get the problem - I was trying to do a simple action:
for(i = x.Length-1, j = 0 ; i >= 0 ; i--, j++)
{
backx[j] = x[i];
}
Both are declared:
String x;
String backx;
What is the problem ? It says the error in the title...
If there is a problem - is there another way to do that?
The result (As the name 'backx' hints) is that backx will contain the string X backwards.
P.S. x is not empty - it contains a substring from another string.
Strings are immutable: you can retrieve the character at a certain position, but you cannot change the character to a new one directly.
Instead you'll have to build a new string with the change. There are several ways to do this, but StringBuilder does the job in a similar fashion to what you already have:
StringBuilder sb = new StringBuilder(backx);
sb[j] = x[i];
backx = sb.ToString();
EDIT: If you take a look at the string public facing API, you'll see this indexer:
public char this[int index] { get; }
This shows that you can "get" a value, but because no "set" is available, you cannot assign values to that indexer.
EDITx2: If you're looking for a way to reverse a string, there are a few different ways, but here's one example with an explanation as to how it works: http://www.dotnetperls.com/reverse-string
String is immutable in .NET - this is why you get the error.
You can get a reverse string with LINQ:
string x = "abcd";
string backx = new string(x.Reverse().ToArray());
Console.WriteLine(backx); // output: "dcba"
String are immuatable. You have convert to Char Array and then you would be able to modify.
Or you can use StringBuilder.
for example
char[] wordArray = word.ToCharArray();
In C# strings are immutable. You cannot "set" Xth character to whatever you want. If yo uwant to construct a new string, or be able to "edit" a string, use i.e. StringBuilder class.
Strings are immutable in C#. You can read more about it here: http://msdn.microsoft.com/en-us/library/362314fe.aspx
Both the variables you have are string while you are treating them as if they were arrays (well, they are). Of course it is a valid statement to access characters from a string through this mechanism, you cannot really assign it that way.
Since you are trying to reverse a string, do take a look at this post. It has lot of information.
public static string ReverseName( string theName)
{
string revName = string.Empty;
foreach (char a in theName)
{
revName = a + revName;
}
return revName;
}
This is simple and does not involve arrays directly.
The code below simply swaps the index of each char in the string which enables you to only have to iterate half way through the original string which is pretty efficient if you're dealing with a lot of characters. The result is the original string reversed. I tested this with a string consisting of 100 characters and it executed in 0.0000021 seconds.
private string ReverseString(string testString)
{
int j = testString.Length - 1;
char[] charArray = new char[testString.Length];
for (int i = 0; i <= j; i++)
{
if (i != j)
{
charArray[i] = testString[j];
charArray[j] = testString[i];
}
j--;
}
return new string(charArray);
}
In case you need to replace e.g. index 2 in string use this (it is ugly, but working and is easily maintainbable)
V1 - you know what you want to put their. Here you saying in pseudocode string[2] = 'R';
row3String.Replace(row3String[2], 'R');
V2 - you need to put their char R or char Y. Here string[2] = 'R' if was 'Y' or if was not stay 'Y' (this one line if needs some form of else)
row3String.Replace(row3String[2], row3String[2].Equals('Y') ? 'R' : 'Y');

What are the alternatives to Split a string in c# that don't use String.Split()

I saw this question that asks given a string "smith;rodgers;McCalne" how can you produce a collection. The answer to this was to use String.Split.
If we don't have Split() built in what do you do instead?
Update:
I admit writing a split function is fairly easy. Below is what I would've wrote. Loop through the string using IndexOf and extract using Substring.
string s = "smith;rodgers;McCalne";
string seperator = ";";
int currentPosition = 0;
int lastPosition = 0;
List<string> values = new List<string>();
do
{
currentPosition = s.IndexOf(seperator, currentPosition + 1);
if (currentPosition == -1)
currentPosition = s.Length;
values.Add(s.Substring(lastPosition, currentPosition - lastPosition));
lastPosition = currentPosition+1;
} while (currentPosition < s.Length);
I took a peek at SSCLI implementation and its similar to the above except it handles way more use cases and it uses an unsafe method to determine the indexes of the separators before doing the substring extraction.
Others have suggested the following.
An Extension Method that uses an Iterator Block
Regex suggestion (no implementation)
Linq Aggregate method
Is this it?
It's reasonably simple to write your own Split equivalent.
Here's a quick example, although in reality you'd probably want to create some overloads for more flexibility. (Well, in reality you'd just use the framework's built-in Split methods!)
string foo = "smith;rodgers;McCalne";
foreach (string bar in foo.Split2(";"))
{
Console.WriteLine(bar);
}
// ...
public static class StringExtensions
{
public static IEnumerable<string> Split2(this string source, string delim)
{
// argument null checking etc omitted for brevity
int oldIndex = 0, newIndex;
while ((newIndex = source.IndexOf(delim, oldIndex)) != -1)
{
yield return source.Substring(oldIndex, newIndex - oldIndex);
oldIndex = newIndex + delim.Length;
}
yield return source.Substring(oldIndex);
}
}
You make your own loop to do the split. Here is one that uses the Aggregate extension method. Not very efficient, as it uses the += operator on the strings, so it should not really be used as anything but an example, but it works:
string names = "smith;rodgers;McCalne";
List<string> split = names.Aggregate(new string[] { string.Empty }.ToList(), (s, c) => {
if (c == ';') s.Add(string.Empty); else s[s.Count - 1] += c;
return s;
});
Regex?
Or just Substring. This is what Split does internally

How should I convert a number with a text suffix to an integer in c#?

What's the cleanest/best way in C# to convert something like 400AMP or 6M to an integer? I won't always know what the suffix is, and I just want whatever it is to go away and leave me with the number.
You could use a regular expression:
Regex reg = new Regex("[0-9]*");
int result = Convert.ToInt32(reg.Match(input));
Okay, here's a long-winded solution which should be reasonably fast. It's similar to Guffa's middle answer, but I've put the conditions inside the body of the loop as I think that's simpler (and allows us to fetch the character just once). It's a matter of personal taste really.
It deliberately doesn't limit the number of digits that it matches, because if the string is an integer which overflows Int32, I think I'd rather see an exception than just a large integer :)
Note that this also handles negative numbers, which I don't think any of the other solutions so far do...
using System;
class Test
{
static void Main()
{
Console.WriteLine(ParseLeadingInt32("-1234AMP"));
Console.WriteLine(ParseLeadingInt32("+1234AMP"));
Console.WriteLine(ParseLeadingInt32("1234AMP"));
Console.WriteLine(ParseLeadingInt32("-1234"));
Console.WriteLine(ParseLeadingInt32("+1234"));
Console.WriteLine(ParseLeadingInt32("1234"));
}
static int ParseLeadingInt32(string text)
{
// Declared before loop because we need the
// final value
int i;
for (i=0; i < text.Length; i++)
{
char c = text[i];
if (i==0 && (c=='-' || c=='+'))
{
continue;
}
if (char.IsDigit(c))
{
continue;
}
break;
}
return int.Parse(text.Substring(0, i));
}
}
It's possibly not the cleanest method, but it's reasonably simple (a one liner) and I would imagine faster than a regex (uncompiled, for sure).
var str = "400AMP";
var num = Convert.ToInt32(str.Substring(0, str.ToCharArray().TakeWhile(
c => char.IsDigit(c)).Count()));
Or as an extension method:
public static int GetInteger(this string value)
{
return Convert.ToInt32(str.Substring(0, str.ToCharArray().TakeWhile(
c => char.IsDigit(c)).Count()));
}
Equivalently, you could construct the numeric string from the result of the TakeWhile function, as such:
public static int GetInteger(this string value)
{
return new string(str.ToCharArray().TakeWhile(
c => char.IsNumber(c)).ToArray());
}
Haven't benchmarked them, so I wouldn't know which is quicker (though I'd very much suspect the first). If you wanted to get better performance, you would just convert the LINQ (extension method calls on enumerables) to a for loop.
Hope that helps.
There are several options...
Like using a regular expression:
int result = int.Parse(Regex.Match(input, #"^\d+").Groups[0].Value);
Among the fastest; simply looping to find digits:
int i = 0;
while (i < input.Length && Char.IsDigit(input, i)) i++;
int result = int.Parse(input.Substring(0, i));
Use LastIndexOfAny to find the last digit:
int i = input.LastIndexOfAny("0123456789".ToCharArray()) + 1;
int result = int.Parse(input.Substring(0, i));
(Note: breaks with strings that has digits after the suffix, like "123asdf123".)
Probably fastest; parse it yourself:
int i = 0;
int result = 0;
while (i < input.Length) {
char c = input[i];
if (!Char.IsDigit(c)) break;
result *= 10;
result += c - '0';
i++;
}
If all you want to do is remove an unknown postfix from what would otherwise be an int, here is how I would do it:
I like a utility static method I call IsInt(string possibleInt) which will, as the name implies, return True if the string will parse into an int. You could write this same static method into your utility class (if it's not there already) and try:
`string foo = "12345SomePostFix";
while (!Tools.ToolBox.IsInt(foo))
{
foo = foo.Remove(foo.Length - 1);
}
int fooInt = int.Parse(foo);`

How to search a string in String array

I need to search a string in the string array. I dont want to use any for looping in it
string [] arr = {"One","Two","Three"};
string theString = "One"
I need to check whether theString variable is present in arr.
Well, something is going to have to look, and looping is more efficient than recursion (since tail-end recursion isn't fully implemented)... so if you just don't want to loop yourself, then either of:
bool has = arr.Contains(var); // .NET 3.5
or
bool has = Array.IndexOf(arr, var) >= 0;
For info: avoid names like var - this is a keyword in C# 3.0.
Every method, mentioned earlier does looping either internally or externally, so it is not really important how to implement it. Here another example of finding all references of target string
string [] arr = {"One","Two","Three"};
var target = "One";
var results = Array.FindAll(arr, s => s.Equals(target));
Does it have to be a string[] ? A List<String> would give you what you need.
List<String> testing = new List<String>();
testing.Add("One");
testing.Add("Two");
testing.Add("Three");
testing.Add("Mouse");
bool inList = testing.Contains("Mouse");
bool exists = arr.Contains("One");
I think it is better to use Array.Exists than Array.FindAll.
Its pretty simple. I always use this code to search string from a string array
string[] stringArray = { "text1", "text2", "text3", "text4" };
string value = "text3";
int pos = Array.IndexOf(stringArray, value);
if (pos > -1)
{
return true;
}
else
{
return false;
}
If the array is sorted, you can use BinarySearch. This is a O(log n) operation, so it is faster as looping. If you need to apply multiple searches and speed is a concern, you could sort it (or a copy) before using it.
Each class implementing IList has a method Contains(Object value). And so does System.Array.
Why the prohibition "I don't want to use any looping"? That's the most obvious solution. When given the chance to be obvious, take it!
Note that calls like arr.Contains(...) are still going to loop, it just won't be you who has written the loop.
Have you considered an alternate representation that's more amenable to searching?
A good Set implementation would perform well. (HashSet, TreeSet or the local equivalent).
If you can be sure that arr is sorted, you could use binary search (which would need to recurse or loop, but not as often as a straight linear search).
You can use Find method of Array type. From .NET 3.5 and higher.
public static T Find<T>(
T[] array,
Predicate<T> match
)
Here is some examples:
// we search an array of strings for a name containing the letter “a”:
static void Main()
{
string[] names = { "Rodney", "Jack", "Jill" };
string match = Array.Find (names, ContainsA);
Console.WriteLine (match); // Jack
}
static bool ContainsA (string name) { return name.Contains ("a"); }
Here’s the same code shortened with an anonymous method:
string[] names = { "Rodney", "Jack", "Jill" };
string match = Array.Find (names, delegate (string name)
{ return name.Contains ("a"); } ); // Jack
A lambda expression shortens it further:
string[] names = { "Rodney", "Jack", "Jill" };
string match = Array.Find (names, n => n.Contains ("a")); // Jack
At first shot, I could come up with something like this (but it's pseudo code and assuming you cannot use any .NET built-in libaries). Might require a bit of tweaking and re-thinking, but should be good enough for a head-start, maybe?
int findString(String var, String[] stringArray, int currentIndex, int stringMaxIndex)
{
if currentIndex > stringMaxIndex
return (-stringMaxIndex-1);
else if var==arr[currentIndex] //or use any string comparison op or function
return 0;
else
return findString(var, stringArray, currentIndex++, stringMaxIndex) + 1 ;
}
//calling code
int index = findString(var, arr, 0, getMaxIndex(arr));
if index == -1 printOnScreen("Not found");
else printOnScreen("Found on index: " + index);
In C#, if you can use an ArrayList, you can use the Contains method, which returns a boolean:
if MyArrayList.Contains("One")
You can check the element existence by
arr.Any(x => x == "One")
it is old one ,but this is the way i do it ,
enter code herevar result = Array.Find(names, element => element == "One");
I'm surprised that no one suggested using Array.IndexOf Method.
Indeed, Array.IndexOf has two advantages :
It allows searching if an element is included into an array,
It gets at the same time the index into the array.
int stringIndex = Array.IndexOf(arr, theString);
if (stringIndex >= 0)
{
// theString has been found
}
Inline version :
if (Array.IndexOf(arr, theString) >= 0)
{
// theString has been found
}
Using Contains()
string [] SomeArray = {"One","Two","Three"};
bool IsExist = SomeArray.Contains("One");
Console.WriteLine("Is string exist: "+ IsExist);
Using Find()
string [] SomeArray = {"One","Two","Three"};
var result = Array.Find(SomeArray, element => element == "One");
Console.WriteLine("Required string is: "+ result);
Another simple & traditional way, very useful for beginners to build logic.
string [] SomeArray = {"One","Two","Three"};
foreach (string value in SomeArray) {
if (value == "One") {
Console.WriteLine("Required string is: "+ value);
}
}

Categories