Change indexed character of string - c#

Im working on a program that changes a specified character, if its uppercase, it will change it to lowercase and vice versa.
I have written a piece of code that in theory should work. I have also written it with a foreach(char c in x) method but that wont work wither. Any tips?
Expected output teSTSTring
Given output TEststRING
string x = "TEststRING";
for (int i = 0; i < x.Length; i++)
{
if (char.IsUpper(x[i]))
{
char.ToLower(x[i]);
}
if (char.IsLower(x[i]))
{
char.ToUpper(x[i]);
}
}
Console.WriteLine(x);

Here is a solution with StringBuilder
string x = "TEststRING";
car sb = new StringBuilder();
foreach (car c in x)
{
if (char.IsUpper(c))
{
sb.Append(char.ToLower(c));
}
else
{
sb.Append(char.ToUpper(c));
}
}
Console.WriteLine(sb.ToString());

You are not changing the input string. I would suggest you use the below code.
It will handle the cases where you have characters other than alphabets as well.
string output = new string(x.Select(c => char.IsLetter(c) ? (char.IsUpper(c) ? char.ToLower(c) : char.ToUpper(c)) : c).ToArray());

Here is an alternative to my foreach version. This alternative will use Linq like vivek nuna's answer. Note that Linq is a powerful part of C#, while you should dig it, it is quite advanced. Here is my version of it:
char SwitchCase(char c) => char.IsUpper(c) ? char.ToLower(c) : char.ToUpper(c);
var x = "TEststRING(1)";
var output = string.Concat(x.Select(SwitchCase));
Console.WriteLine(output);
Changes include:
Use string.Concat to, well, concat the IEnumerable into a string instead of using ToArray() with new string()
Remove the char.IsLetter check, ToUpper already handles it.
Create a SwitchCase function to name the logic
Try it online!

Related

how to censor the first 10 char in a string using c#

so I want to create a credit card encoder (if this even a word) that takes a string and put the first 10 digits of the string as '*'
this is the code I came up with:
public static string[] ToCencoredString(this string str)
{
char[] array = Enumerable.Repeat('*', str.Length-1).ToArray();
array = array.Select((cha, index) =>
{
if (index < 10)
array[index] = str[index];
});
}
(ignoringe the fact the function returns string[] there is another part of the code which is not relevant)
I don't know why, but I keep getting ArgumentNullException which is odd because there is not a single value in array witch is null.
what am I doing wrong?
What about changing it to something a bit more simple:
var result = string.Concat(Enumerable.Repeat("*", 10)) + str.Substring(10);
I'd use this more efficient version using String.Substring and the string constructor:
public static string ToCencoredString(this string str, int length = 10)
{
if (String.IsNullOrEmpty(str)) return str;
string censored = new string('*', length);
if (str.Length <= length) return censored;
return censored + str.Substring(length);
}
I suggest you use the original array for iterating so that you can make use of its index to create the mask. A String.Join() may help you to produce the masked output. The code would be something like this:
string maskedInput = String.Join("", str.Select((c, index) => index < 10? '*' : c));
Here is a working example for your reference
Your code doesn't compile. So I dont know how you managed to reach ArgumentNullException.
And that's not how you use LINQ. The correct way (although not a good way, since the answers above are apparently way better) to implement what's in your mind
array = array.Select((cha, index) =>
{
if (index < 10)
return array[index];
else
return str[index];
}).ToArray();
$"{string.Concat(Enumerable.Repeat("*", 10))}{FIELD.Substring(10)}";

C# - Dealing with contradictions in string.replace

I'm getting started with C# and programming in general and I've been playing with the "if" statements, arrays and generally getting to grips with things. However, one thing that has stumped me is how you would go about performing an replace operation which is inherently contradictory.
IE: I have string "AAABBB" but I want to search through my text and replace all "A"s with "B"s and vice-versa. So my intended output would be "BBBAAA".
I'm currently trying to use string.replace and if statements but it's not working (it follows the order of the statements, so in the above examples I'd get all "A" or all "B".
Code examples:
if (string.Contains("a"));
{
string = string.Replace("a", "b");
}
if (string.Contains("b"));
{
string = string.Replace("b", "a");
}
Any help would be super welcome!
If you're always replacing one character with another, it's probably simplest to convert it to a char[] and go through it one character at a time, fixing each one appropriately - rather than doing "all the As" and then "all the Bs".
public static string PerformReplacements(string text)
{
char[] chars = text.ToCharArray();
for (int i = 0; i < chars.Length; i++)
{
switch (chars[i])
{
case 'A':
chars[i] = 'B';
break;
case 'B':
chars[i] = 'A';
break;
}
}
return new string(chars);
}
Consider using Linq:
s = new string(s.Select(x => x == 'A' ? 'B' : x == 'B' ? 'A' : x).ToArray());
The reason why this fails is because all A's are first replaced by B's but then back to A's.
A generic way to solve this is the following:
using System.Linq;
using System.Text;
using System.Diagnostics.Contracts;
public class Foo {
public static string ParallelReplace (string text, char[] fromc, char[] toc) {
Contract.Requires(text != null);
Contract.Requires(fromc != null);
Contract.Requires(toc != null)
Contract.Requires(fromc.Length == toc.Length);
Contract.Ensures(Contract.Result<string>().Length == text.Length);
Array.Sort(fromc,toc);
StringBuilder sb = new StringBuilder();
foreach(char c in text) {
int i = Array.BinarySearch(fromc,c);
if(i >= 0) {
sb.Append(toc[i]);
} else {
sb.Append(c);
}
}
return sb.ToString();
}
}
Demo with csharp interactive shell:
csharp> Foo.ParallelReplace("ABasdsadsadaABABB",new char[] {'b','a','s'},new char[] {'f','s','a'});
"ABsadasdasdsABABB"
This represents a mapping {b->f,a->s,s->a}. The method works in O(s*log(n)+n*log(n)), with s the length of the string and n the number of rules.
The Contract's are not necessary, but can help if one uses a static code analysis tool to prevent making errors.

How to convert string to decimal[] in C#

Is there a way to achieve this?
I tried:
string str = "{34.10,0,0.00}"; //the string as I get it from Postgres DB
decimal[] won;
won = (decimal[])(str); //Cannot convert type 'string' to 'decimal[]'
What I would ideally want is to get into won:
won[0] = 34.10
won[1] = 0
won[2] = 0.00
Surely, I can go and split by commas, and put it in the array but I'm wondering if there's a better way.
You have to Split
won = str.Trim('{', '}').Split(',').Select(decimal.Parse).ToArray();
Edit: This part is just for fun
There is no way to cast string to a decimal[] array directly, but if you want you can add a decimal wrapper class and define implicit conversions:
class MyDecimal
{
private decimal[] _values;
public MyDecimal(int size)
{
_values = new decimal[size];
}
public decimal this[int index]
{
get { return _values[index]; }
set { _values[index] = value; }
}
public static implicit operator MyDecimal(string str)
{
var numbers = str.Trim('{', '}').Split(',');
MyDecimal d = new MyDecimal(numbers.Length);
d._values = numbers
.Select(x => decimal.Parse(x,CultureInfo.InvariantCulture))
.ToArray();
return d;
}
public static implicit operator string(MyDecimal md)
{
return string.Join(",", md._values);
}
}
Then you can do:
string str = "{34.10,0,0.00}"; //the string as I get it from Postgres DB
MyDecimal won = str;
I first misread your question. The real answer is: I know of no other way than splitting and converting in loops or using LINQ (for a LINQ sample see Selman22's answer). There's no way to cast a string to an array in one go.
While it is essentially what you suggest, you could try this:
// Remove leading and trailing brackets
string s = str.Trim('{', '}');
// Split numbers
string[] parts = s.Split(',');
decimal[] nums = new decimal[parts.Length];
// Convert
for (int i = 0; i < parts.Length; i++)
nums[i] = Convert.ToDecimal(parts[i]);
Just to play devil's advocate to those who say you have no option but to split:
var result = new JavaScriptSerializer()
.Deserialize<decimal[]>(str.Replace('{', '[').Replace('}', ']'))
here is another but probably not a better way in regex
string str = "{34.10,0,0.00}";
string pattern = #"([\d]+[\.]|[\d]?)[\d]+";
decimal[] result = Regex.Matches(str, pattern, RegexOptions.None)
.Cast<Match>()
.Select(x => decimal.Parse(x.Value))
.ToArray();
but remember Jamie Zawinski:
Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems.
Another way would be using a StringReader and managing the split
There is no better way. At least until C# is backed up by an AI which will just guess what you are trying to do by casting one datatype into another by a custom logic.
Any programmer would guess what you want. Until now though the C# compiler is no wizard.

Property or indexer 'string.this[int]' cannot be assigned to -- it's read only

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');

int array to string

In C#, I have an array of ints, containing digits only. I want to convert this array to string.
Array example:
int[] arr = {0,1,2,3,0,1};
How can I convert this to a string formatted as: "012301"?
at.net 3.5 use:
String.Join("", new List<int>(array).ConvertAll(i => i.ToString()).ToArray());
at.net 4.0 or above use: (see #Jan Remunda's answer)
string result = string.Join("", array);
You can simply use String.Join function, and as separator use string.Empty because it uses StringBuilder internally.
string result = string.Join(string.Empty, new []{0,1,2,3,0,1});
E.g.: If you use semicolon as separator, the result would be 0;1;2;3;0;1.
It actually works with null separator, and second parameter can be enumerable of any objects, like:
string result = string.Join(null, new object[]{0,1,2,3,0,"A",DateTime.Now});
I realize my opinion is probably not the popular one, but I guess I have a hard time jumping on the Linq-y band wagon. It's nifty. It's condensed. I get that and I'm not opposed to using it where it's appropriate. Maybe it's just me, but I feel like people have stopped thinking about creating utility functions to accomplish what they want and instead prefer to litter their code with (sometimes) excessively long lines of Linq code for the sake of creating a dense 1-liner.
I'm not saying that any of the Linq answers that people have provided here are bad, but I guess I feel like there is the potential that these single lines of code can start to grow longer and more obscure as you need to handle various situations. What if your array is null? What if you want a delimited string instead of just purely concatenated? What if some of the integers in your array are double-digit and you want to pad each value with leading zeros so that the string for each element is the same length as the rest?
Taking one of the provided answers as an example:
result = arr.Aggregate(string.Empty, (s, i) => s + i.ToString());
If I need to worry about the array being null, now it becomes this:
result = (arr == null) ? null : arr.Aggregate(string.Empty, (s, i) => s + i.ToString());
If I want a comma-delimited string, now it becomes this:
result = (arr == null) ? null : arr.Skip(1).Aggregate(arr[0].ToString(), (s, i) => s + "," + i.ToString());
This is still not too bad, but I think it's not obvious at a glance what this line of code is doing.
Of course, there's nothing stopping you from throwing this line of code into your own utility function so that you don't have that long mess mixed in with your application logic, especially if you're doing it in multiple places:
public static string ToStringLinqy<T>(this T[] array, string delimiter)
{
// edit: let's replace this with a "better" version using a StringBuilder
//return (array == null) ? null : (array.Length == 0) ? string.Empty : array.Skip(1).Aggregate(array[0].ToString(), (s, i) => s + "," + i.ToString());
return (array == null) ? null : (array.Length == 0) ? string.Empty : array.Skip(1).Aggregate(new StringBuilder(array[0].ToString()), (s, i) => s.Append(delimiter).Append(i), s => s.ToString());
}
But if you're going to put it into a utility function anyway, do you really need it to be condensed down into a 1-liner? In that case why not throw in a few extra lines for clarity and take advantage of a StringBuilder so that you're not doing repeated concatenation operations:
public static string ToStringNonLinqy<T>(this T[] array, string delimiter)
{
if (array != null)
{
// edit: replaced my previous implementation to use StringBuilder
if (array.Length > 0)
{
StringBuilder builder = new StringBuilder();
builder.Append(array[0]);
for (int i = 1; i < array.Length; i++)
{
builder.Append(delimiter);
builder.Append(array[i]);
}
return builder.ToString()
}
else
{
return string.Empty;
}
}
else
{
return null;
}
}
And if you're really so concerned about performance, you could even turn it into a hybrid function that decides whether to do string.Join or to use a StringBuilder depending on how many elements are in the array (this is a micro-optimization, not worth doing in my opinion and possibly more harmful than beneficial, but I'm using it as an example for this problem):
public static string ToString<T>(this T[] array, string delimiter)
{
if (array != null)
{
// determine if the length of the array is greater than the performance threshold for using a stringbuilder
// 10 is just an arbitrary threshold value I've chosen
if (array.Length < 10)
{
// assumption is that for arrays of less than 10 elements
// this code would be more efficient than a StringBuilder.
// Note: this is a crazy/pointless micro-optimization. Don't do this.
string[] values = new string[array.Length];
for (int i = 0; i < values.Length; i++)
values[i] = array[i].ToString();
return string.Join(delimiter, values);
}
else
{
// for arrays of length 10 or longer, use a StringBuilder
StringBuilder sb = new StringBuilder();
sb.Append(array[0]);
for (int i = 1; i < array.Length; i++)
{
sb.Append(delimiter);
sb.Append(array[i]);
}
return sb.ToString();
}
}
else
{
return null;
}
}
For this example, the performance impact is probably not worth caring about, but the point is that if you are in a situation where you actually do need to be concerned with the performance of your operations, whatever they are, then it will most likely be easier and more readable to handle that within a utility function than using a complex Linq expression.
That utility function still looks kind of clunky. Now let's ditch the hybrid stuff and do this:
// convert an enumeration of one type into an enumeration of another type
public static IEnumerable<TOut> Convert<TIn, TOut>(this IEnumerable<TIn> input, Func<TIn, TOut> conversion)
{
foreach (TIn value in input)
{
yield return conversion(value);
}
}
// concatenate the strings in an enumeration separated by the specified delimiter
public static string Delimit<T>(this IEnumerable<T> input, string delimiter)
{
IEnumerator<T> enumerator = input.GetEnumerator();
if (enumerator.MoveNext())
{
StringBuilder builder = new StringBuilder();
// start off with the first element
builder.Append(enumerator.Current);
// append the remaining elements separated by the delimiter
while (enumerator.MoveNext())
{
builder.Append(delimiter);
builder.Append(enumerator.Current);
}
return builder.ToString();
}
else
{
return string.Empty;
}
}
// concatenate all elements
public static string ToString<T>(this IEnumerable<T> input)
{
return ToString(input, string.Empty);
}
// concatenate all elements separated by a delimiter
public static string ToString<T>(this IEnumerable<T> input, string delimiter)
{
return input.Delimit(delimiter);
}
// concatenate all elements, each one left-padded to a minimum length
public static string ToString<T>(this IEnumerable<T> input, int minLength, char paddingChar)
{
return input.Convert(i => i.ToString().PadLeft(minLength, paddingChar)).Delimit(string.Empty);
}
Now we have separate and fairly compact utility functions, each of which are arguable useful on their own.
Ultimately, my point is not that you shouldn't use Linq, but rather just to say don't forget about the benefits of creating your own utility functions, even if they are small and perhaps only contain a single line that returns the result from a line of Linq code. If nothing else, you'll be able to keep your application code even more condensed than you could achieve with a line of Linq code, and if you are using it in multiple places, then using a utility function makes it easier to adjust your output in case you need to change it later.
For this problem, I'd rather just write something like this in my application code:
int[] arr = { 0, 1, 2, 3, 0, 1 };
// 012301
result = arr.ToString<int>();
// comma-separated values
// 0,1,2,3,0,1
result = arr.ToString(",");
// left-padded to 2 digits
// 000102030001
result = arr.ToString(2, '0');
To avoid the creation of an extra array you could do the following.
var builder = new StringBuilder();
Array.ForEach(arr, x => builder.Append(x));
var res = builder.ToString();
string result = arr.Aggregate("", (s, i) => s + i.ToString());
(Disclaimer: If you have a lot of digits (hundreds, at least) and you care about performance, I suggest eschewing this method and using a StringBuilder, as in JaredPar's answer.)
You can do:
int[] arr = {0,1,2,3,0,1};
string results = string.Join("",arr.Select(i => i.ToString()).ToArray());
That gives you your results.
I like using StringBuilder with Aggregate(). The "trick" is that Append() returns the StringBuilder instance itself:
var sb = arr.Aggregate( new StringBuilder(), ( s, i ) => s.Append( i ) );
var result = sb.ToString();
string.Join("", (from i in arr select i.ToString()).ToArray())
In the .NET 4.0 the string.Join can use an IEnumerable<string> directly:
string.Join("", from i in arr select i.ToString())
I've left this here for posterity but don't recommend its use as it's not terribly readable. This is especially true now that I've come back to see if after a period of some time and have wondered what I was thinking when I wrote it (I was probably thinking 'crap, must get this written before someone else posts an answer'.)
string s = string.Concat(arr.Cast<object>().ToArray());
The most efficient way is not to convert each int into a string, but rather create one string out of an array of chars. Then the garbage collector only has one new temp object to worry about.
int[] arr = {0,1,2,3,0,1};
string result = new string(Array.ConvertAll<int,char>(arr, x => Convert.ToChar(x + '0')));
This is a roundabout way to go about it its not much code and easy for beginners to understand
int[] arr = {0,1,2,3,0,1};
string joined = "";
foreach(int i in arr){
joined += i.ToString();
}
int number = int.Parse(joined);
If this is long array you could use
var sb = arr.Aggregate(new StringBuilder(), ( s, i ) => s.Append( i ), s.ToString());
// This is the original array
int[] nums = {1, 2, 3};
// This is an empty string we will end up with
string numbers = "";
// iterate on every char in the array
foreach (var item in nums)
{
// add the char to the empty string
numbers += Convert.ToString(item);
}
// Write the string in the console
Console.WriteLine(numbers);

Categories

Resources