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)}";
Got stuck with this.. can you please explain what is happening in it? or give me any link!
String s1="C# Example";
Char[] s3 = s1.ToCharArray();
Console.WriteLine("S3 : {0}",s3);
I want to display the Character which is converted. Output displayed is System.Char[]. Now i need to do some changes, but what is that ?
It is possible in two ways.
1) I need to Change it to String, before i'm going to Print.
Or
2) I need to print it with Char by defining the index, (i.e) s3[0];
Am i correct. Anything More?
The explanation of what happens:
Console.WriteLine("{0}", s3) calls s3.ToString().
Because WriteLine() calls ToString() on each argument
Method ToString() isn't overridden in type System.Array so Object.ToString() is called.
Because Char[] is System.Array and all types inherit from Systen.Object.
Which is equivalent to s3.GetType().ToString() and outputs System.Char[].
Because this is the default implementation. Subtypes can override it. For instance, System.String does, StringBuilder too.
Solution A:
If you want to display the characters individually on console then you need to get each character separately and display it using a loop.
foreach(char ch in s3)
{
Console.WriteLine("S3 : {0}", ch);
}
or, using for-loop,
for (int i = 0; i < s3.Length; i++)
{
Console.WriteLine("S3 : {0}", s3[i]);
}
Solution B :
There's anbther way that I prefer which might not be helpful for you but for those who always looks into better solutions it can be an option also.
Use Extension methods,
Add this class with the extension method in your solution,
public static class DisplayExtension
{
public static string DisplayResult(this string input)
{
var resultString = "";
foreach (char ch in input.ToCharArray())
{
resultString += "S3 : " + ch.ToString() + "\n";
}
return resultString;
}
}
And call the DisplayResult() extension method from your program like this,
Console.WriteLine(s1.DisplayResult());
This will give you the same result but extend the re-usability of your code without writing the for loop for all the repeated situation.
Good answers so far, and great explanation from #abatishchev on why WriteLine() prints System.Char[]
How ever I would like to add an additional solution, because using loops inside your WriteLine() will look confusing and its not very pleasing to the eye. For better readability you can use new string()
In this example it would look like this:
String s1="C# Example";
Char[] s3 = s1.ToCharArray();
Console.WriteLine("S3 : {0}",new string(s3));
Console.WriteLine("S3 : {0}",s3);
gives result s3.ToString() which results System.Char[]
Instead create a for loop like:
Console.Write("S3 :");
for(int i=0; i<s3.Length; i++)
{
Console.Write(s3[i]);
}
which gives desired output
char [] str = new char[20];
Suppose str is the character array, and we need to display it. Do the following (provided you enter something in the str using loop):
Console.WriteLine("The string is: {0}", string.Join("",str));
Here, each character in str is joined and displayed.
Suppose I have a string:
"34234234d124"
I want to get the last four characters of this string which is "d124". I can use SubString, but it needs a couple of lines of code, including naming a variable.
Is it possible to get this result in one expression with C#?
mystring.Substring(Math.Max(0, mystring.Length - 4)); //how many lines is this?
If you're positive the length of your string is at least 4, then it's even shorter:
mystring.Substring(mystring.Length - 4);
You can use an extension method:
public static class StringExtension
{
public static string GetLast(this string source, int tail_length)
{
if(tail_length >= source.Length)
return source;
return source.Substring(source.Length - tail_length);
}
}
And then call:
string mystring = "34234234d124";
string res = mystring.GetLast(4);
Update 2020: C# 8.0 finally makes this easy:
> "C# 8.0 finally makes this easy"[^4..]
"easy"
You can also slice arrays in the same way, see Indices and ranges.
All you have to do is..
String result = mystring.Substring(mystring.Length - 4);
Ok, so I see this is an old post, but why are we rewriting code that is already provided in the framework?
I would suggest that you add a reference to the framework DLL "Microsoft.VisualBasic"
using Microsoft.VisualBasic;
//...
string value = Strings.Right("34234234d124", 4);
string mystring = "34234234d124";
mystring = mystring.Substring(mystring.Length-4)
Using Substring is actually quite short and readable:
var result = mystring.Substring(mystring.Length - Math.Min(4, mystring.Length));
// result == "d124"
Here is another alternative that shouldn't perform too badly (because of deferred execution):
new string(mystring.Reverse().Take(4).Reverse().ToArray());
Although an extension method for the purpose mystring.Last(4) is clearly the cleanest solution, albeit a bit more work.
You can simply use Substring method of C#. For ex.
string str = "1110000";
string lastFourDigits = str.Substring((str.Length - 4), 4);
It will return result 0000.
A simple solution would be:
string mystring = "34234234d124";
string last4 = mystring.Substring(mystring.Length - 4, 4);
Definition:
public static string GetLast(string source, int last)
{
return last >= source.Length ? source : source.Substring(source.Length - last);
}
Usage:
GetLast("string of", 2);
Result:
of
string var = "12345678";
var = var[^4..];
// var = "5678"
This is index operator that literally means "take last four chars from end (^4) until the end (..)"
mystring = mystring.Length > 4 ? mystring.Substring(mystring.Length - 4, 4) : mystring;
Compared to some previous answers, the main difference is that this piece of code takes into consideration when the input string is:
Null
Longer than or matching the requested length
Shorter than the requested length.
Here it is:
public static class StringExtensions
{
public static string Right(this string str, int length)
{
return str.Substring(str.Length - length, length);
}
public static string MyLast(this string str, int length)
{
if (str == null)
return null;
else if (str.Length >= length)
return str.Substring(str.Length - length, length);
else
return str;
}
}
It is just this:
int count = 4;
string sub = mystring.Substring(mystring.Length - count, count);
I would like to extend the existing answer mentioning using new ranges in C# 8 or higher: To make the code usable for all possible strings, even those shorter than 4, there is some form of condition needed! If you want to copy code, I suggest example 5 or 6.
string mystring ="C# 8.0 finally makes slicing possible";
1: Slicing taking the end part- by specifying how many characters to omit from the beginning- this is, what VS 2019 suggests:
string example1 = mystring[Math.Max(0, mystring.Length - 4)..] ;
2: Slicing taking the end part- by specifying how many characters to take from the end:
string example2 = mystring[^Math.Min(mystring.Length, 4)..] ;
3: Slicing taking the end part- by replacing Max/Min with the ?: operator:
string example3 = (mystring.length > 4)? mystring[^4..] : mystring);
Personally, I like the second and third variant more than the first.
MS doc reference for Indices and ranges:
Null? But we are not done yet concerning universality. Every example so far will throw an exception for null strings. To consider null (if you don´t use non-nullable strings with C# 8 or higher), and to do it without 'if' (classic example 'with if' already given in another answer) we need:
4: Slicing considering null- by specifying how many characters to omit:
string example4 = mystring?[Math.Max(0, mystring.Length - 4)..] ?? string.Empty;
5: Slicing considering null- by specifying how many characters to take:
string example5 = mystring?[^Math.Min(mystring.Length, 4)..] ?? string.Empty;
6: Slicing considering null with the ?: operator (and two other '?' operators ;-) :
(You cannot put that in a whole in a string interpolation e.g. for WriteLine.)
string example6 = (mystring?.Length > 4) ? filePath[^4..] : mystring ?? string.Empty;
7: Equivalent variant with good old Substring() for C# 6 or 7.x:
(You cannot put that in a whole in a string interpolation e.g. for WriteLine.)
string example7 = (mystring?.Length > 4) ? mystring.Substring(mystring.Length- 4) : mystring ?? string.Empty;
Graceful degradation?
I like the new features of C#. Putting them on one line like in the last examples maybe looks a bit excessive. We ended up a little perl´ish didn´t we?
But it´s a good example for learning and ok for me to use it once in a tested library method.
Even better that we can get rid of null in modern C# if we want and avoid all this null-specific handling.
Such a library/extension method as a shortcut is really useful. Despite the advances in C# you have to write your own to get something easier to use than repeating the code above for every small string manipulation need.
I am one of those who began with BASIC, and 40 years ago there was already Right$(,). Funny, that it is possible to use Strings.Right(,) from VB with C# still too as was shown in another answer.
C# has chosen precision over graceful degradation (in opposite to old BASIC).
So copy any appropriate variant you like in these answers and define a graceful shortcut function for yourself, mine is an extension function called RightChars(int).
This works nice, as there are no errors if there are less characters in the string than the requested amount.
using System.Linq;
string.Concat("123".TakeLast(4));
This won't fail for any length string.
string mystring = "34234234d124";
string last4 = Regex.Match(mystring, "(?!.{5}).*").Value;
// last4 = "d124"
last4 = Regex.Match("d12", "(?!.{5}).*").Value;
// last4 = "d12"
This is probably overkill for the task at hand, but if there needs to be additional validation, it can possibly be added to the regular expression.
Edit: I think this regex would be more efficient:
#".{4}\Z"
Using the range operator is the easiest way for me. No many codes is required.
In your case, you can get what you want like this:
// the ^ operator indicates the element position from the end of a sequence
string str = "34234234d124"[^4..]
string x = "34234234d124";
string y = x.Substring(x.Length - 4);
Use a generic Last<T>. That will work with ANY IEnumerable, including string.
public static IEnumerable<T> Last<T>(this IEnumerable<T> enumerable, int nLastElements)
{
int count = Math.Min(enumerable.Count(), nLastElements);
for (int i = enumerable.Count() - count; i < enumerable.Count(); i++)
{
yield return enumerable.ElementAt(i);
}
}
And a specific one for string:
public static string Right(this string str, int nLastElements)
{
return new string(str.Last(nLastElements).ToArray());
}
Suggest using TakeLast method, for example: new String(text.TakeLast(4).ToArray())
I threw together some code modified from various sources that will get the results you want, and do a lot more besides. I've allowed for negative int values, int values that exceed the length of the string, and for end index being less than the start index. In that last case, the method returns a reverse-order substring. There are plenty of comments, but let me know if anything is unclear or just crazy. I was playing around with this to see what all I might use it for.
/// <summary>
/// Returns characters slices from string between two indexes.
///
/// If start or end are negative, their indexes will be calculated counting
/// back from the end of the source string.
/// If the end param is less than the start param, the Slice will return a
/// substring in reverse order.
///
/// <param name="source">String the extension method will operate upon.</param>
/// <param name="startIndex">Starting index, may be negative.</param>
/// <param name="endIndex">Ending index, may be negative).</param>
/// </summary>
public static string Slice(this string source, int startIndex, int endIndex = int.MaxValue)
{
// If startIndex or endIndex exceeds the length of the string they will be set
// to zero if negative, or source.Length if positive.
if (source.ExceedsLength(startIndex)) startIndex = startIndex < 0 ? 0 : source.Length;
if (source.ExceedsLength(endIndex)) endIndex = endIndex < 0 ? 0 : source.Length;
// Negative values count back from the end of the source string.
if (startIndex < 0) startIndex = source.Length + startIndex;
if (endIndex < 0) endIndex = source.Length + endIndex;
// Calculate length of characters to slice from string.
int length = Math.Abs(endIndex - startIndex);
// If the endIndex is less than the startIndex, return a reversed substring.
if (endIndex < startIndex) return source.Substring(endIndex, length).Reverse();
return source.Substring(startIndex, length);
}
/// <summary>
/// Reverses character order in a string.
/// </summary>
/// <param name="source"></param>
/// <returns>string</returns>
public static string Reverse(this string source)
{
char[] charArray = source.ToCharArray();
Array.Reverse(charArray);
return new string(charArray);
}
/// <summary>
/// Verifies that the index is within the range of the string source.
/// </summary>
/// <param name="source"></param>
/// <param name="index"></param>
/// <returns>bool</returns>
public static bool ExceedsLength(this string source, int index)
{
return Math.Abs(index) > source.Length ? true : false;
}
So if you have a string like "This is an extension method", here are some examples and results to expect.
var s = "This is an extension method";
// If you want to slice off end characters, just supply a negative startIndex value
// but no endIndex value (or an endIndex value >= to the source string length).
Console.WriteLine(s.Slice(-5));
// Returns "ethod".
Console.WriteLine(s.Slice(-5, 10));
// Results in a startIndex of 22 (counting 5 back from the end).
// Since that is greater than the endIndex of 10, the result is reversed.
// Returns "m noisnetxe"
Console.WriteLine(s.Slice(2, 15));
// Returns "is is an exte"
Hopefully this version is helpful to someone. It operates just like normal if you don't use any negative numbers, and provides defaults for out of range params.
string var = "12345678";
if (var.Length >= 4)
{
var = var.substring(var.Length - 4, 4)
}
// result = "5678"
assuming you wanted the strings in between a string which is located 10 characters from the last character and you need only 3 characters.
Let's say StreamSelected = "rtsp://72.142.0.230:80/SMIL-CHAN-273/4CIF-273.stream"
In the above, I need to extract the "273" that I will use in database query
//find the length of the string
int streamLen=StreamSelected.Length;
//now remove all characters except the last 10 characters
string streamLessTen = StreamSelected.Remove(0,(streamLen - 10));
//extract the 3 characters using substring starting from index 0
//show Result is a TextBox (txtStreamSubs) with
txtStreamSubs.Text = streamLessTen.Substring(0, 3);
public static string Last(this string source, int tailLength)
{
return tailLength >= source.Length ? source : source[^tailLength..];
}
This is a bit more than the OP question, but is an example of how to use the last 3 of a string for a specific purpose. In my case, I wanted to do a numerical sort (LINQ OrderBy) on a number field that is stored as a string (1 to 3 digit numbers.) So, to get the string numbers to sort like numeric numbers, I need to left-pad the string numbers with zeros and then take the last 3. The resulting OrderBy statement is:
myList = myList.OrderBy(x => string.Concat("00",x.Id)[^3..])
The string.Concat() used in the OrderBy statement results in strings like "001", "002", "011", "021", "114" which sort the way they would if they were stored as numbers.
I'm trying to maniplulate a string without making a big issue out of it and spreading it out onto multiple lines, so I'm using some chaining to achieve this. The question I have is, how do I use string.Substring() to drop the last character off my string in this context?
In PHP I can pass a negative number as an argument (i.e. substr(-1)) to achieve this, but obviously this isn't how C# works.
mystring = mystring.Replace('_', ' ').Substring(???);
Also, what is the actual name for the technique used above? I always referred to it as a callback chain, but a callback chain I now think is something completely different.
Please note I want to avoid:
mystring = mystring.Replace('_', ' ');
mystring = mystring.Substring(0, mystring.Length - 1);
Thanks in advance for your time and kind consideration.
Iain
Thanks for your answers guys. It's funny that people can have such strong opinions about string manipulation and other "competing" languages :)
You could write an Extension method RightStrip(). You can't overload SubString for negative start positions.
static string RightStrip(this string s, int n)
{
return s.Substring(0, s.Length - n);
}
string s = "Hello World!";
s = s.Replace('e', 'a').RightStrip(1);
Create an extension class like this:
public static class MyStringExtensions
{
public static string RemoveCharactersFromEnd(this string s, int n)
{
string result = string.Empty;
if (string.IsNullOrEmpty(s) == false && n > 0)
{
result = s.Remove(s.Length - n, n);
}
return result;
}
}
Call it:
Console.WriteLine("test!!".RemoveCharactersFromEnd(2));
In your sample, you are chaining to a method that doesn't change the length of the original string. Hence answers suggesting using SubString with (originalLength-1), which of course doesn't work in the general case.
The answer as you seem to have realized is - you can't do it in the general case, where previous methods in the chain have modified the length.
But you can write your own extension method in 3.5 to do what you want. Something like the following or a variant thereof:
public static string PhpSubstring(this string value, int length)
{
if (length < 0) length = value.Length - length;
return String.Substring(value, length);
}
Besides everyone else mentioning the term method chaining, or what some call a fluent interface, I had a note or two I wanted to add.
What I wanted to suggest is that the cool thing about extension methods is that you can easily define your own type of transformation functions that feel the same as this, including system methods such as Replace and ToLower, etc.... something that takes some input and returns some kind of transformed string.
The particular transformation you are asking for (cut off the right-most char) might seem clunky if you have to use Substring directly, but you can hide this away neatly in something like:
public string CutOff(this string s, int c)
{
return s.Substring(0, s.Length - c);
}
...
return myVal.CutOff(1);
(or at least, i think this should work!)
Best of luck!
Method chaining is the term you're looking for. It's true that you cannot pass a negative character like that, but you can still chain the methods:
mystring = mystring.Replace('_', ' ').Substring(0, mystring.Length - 1);
since the string replace in this case, does not affect the length of the string
mystring = mystring.Replace('_', ' ').Remove(mystring.length -1)
However I would consider this a bad idea since the assignment of mystring doesn't happen until after all the manipulation and change in the length of the string in previous calls will result in unexpected behavior.
To further Konamiman's comment:
Just because PHP allows bizarre (and frankly dirty and dangerous) overloads and parameters such as negative starts and counts in SubString, it doesn't mean it's the right, correct or proper way of doing it.
Substring(0, mystring.Length - 1) is the de facto way of trimming off the last character of a string in a wide variety of languages.
You could always use regex:
mystring = new Regex("^(.*).$").Match(mystring.Replace('_', ' ')).Groups[1].Value;
Also, since you're just going to remove that last character, it does not matter if it was a '_' that got replaced by a ' '. This would work just fine:
mystring = mystring.Substring(0, mystring.Length - 1).Replace('_', ' ');