Issue in printing Char Array() which is converted from String - c#

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.

Related

Array.ToString() returning System.Char[] c#

Im making a hangman game, at the start of the game the word that the player must guess is printed as stars. I have just started making it again after attempting to write it once and just having messy code that i couldn't bug fix. So I decided it best to write it again. The only problem is, when i try to get my array to print out by using array.ToString(); it just returns System.char[]. See below.
code:
class Program
{
static void Main(string[] args)
{
string PlayerOneWord;
string PlayerTwoGuess;
int lives = 5;
Console.WriteLine("Welcome to hangman!\n PLayer one, Please enter the word which player Two needs to guess!");
PlayerOneWord = Console.ReadLine().ToLower();
var stars = new char[PlayerOneWord.Length];
for (int i = 0; i < stars.Length ; i++)
{
stars[i] = '*';
}
string StarString = stars.ToString();
Console.Write("Word to Guess: {0}" , StarString);
Console.ReadLine();
}
}
output:
The output should say Word to guess: Hello.
Please will someone explain why this is happening as its not the first time I have run into this problem.
Calling ToString on a simple array only returns "T[]" regardless what the type T is. It doesn't have any special handling for char[].
To convert a char[] to string you can use:
string s = new string(charArray);
But for your concrete problem there is an even simpler solution:
string stars = new string('*', PlayerOneWord.Length);
The constructor public String(char c, int count) repeats c count times.
The variable stars is an array of chars. This is the reason you get this error. As it is stated in MSDN
Returns a string that represents the current object.
In order you get a string from the characters in this array, you could use this:
Console.Write("Word to Guess: {0}" , new String(stars));
The correct way to do this would be:
string StarString = new string(stars);
ToString() calls the standard implementation of the Array-class's ToString-method which is the same for all Arrays and similarily to object only returns the fully qualified class name.
Try this code:
static string ConvertCharArr2Str(char[] chs)
{
var s = "";
foreach (var c in chs)
{
s += c;
}
return s;
}

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

Best way to remove the last character from a string built with stringbuilder

I have the following
data.AppendFormat("{0},",dataToAppend);
The problem with this is that I am using it in a loop and there will be a trailing comma. What is the best way to remove the trailing comma?
Do I have to change data to a string and then substring it?
The simplest and most efficient way is to perform this command:
data.Length--;
by doing this you move the pointer (i.e. last index) back one character but you don't change the mutability of the object. In fact, clearing a StringBuilder is best done with Length as well (but do actually use the Clear() method for clarity instead because that's what its implementation looks like):
data.Length = 0;
again, because it doesn't change the allocation table. Think of it like saying, I don't want to recognize these bytes anymore. Now, even when calling ToString(), it won't recognize anything past its Length, well, it can't. It's a mutable object that allocates more space than what you provide it, it's simply built this way.
Just use
string.Join(",", yourCollection)
This way you don't need the StringBuilder and the loop.
Long addition about async case. As of 2019, it's not a rare setup when the data are coming asynchronously.
In case your data are in async collection, there is no string.Join overload taking IAsyncEnumerable<T>. But it's easy to create one manually, hacking the code from string.Join:
public static class StringEx
{
public static async Task<string> JoinAsync<T>(string separator, IAsyncEnumerable<T> seq)
{
if (seq == null)
throw new ArgumentNullException(nameof(seq));
await using (var en = seq.GetAsyncEnumerator())
{
if (!await en.MoveNextAsync())
return string.Empty;
string firstString = en.Current?.ToString();
if (!await en.MoveNextAsync())
return firstString ?? string.Empty;
// Null separator and values are handled by the StringBuilder
var sb = new StringBuilder(256);
sb.Append(firstString);
do
{
var currentValue = en.Current;
sb.Append(separator);
if (currentValue != null)
sb.Append(currentValue);
}
while (await en.MoveNextAsync());
return sb.ToString();
}
}
}
If the data are coming asynchronously but the interface IAsyncEnumerable<T> is not supported (like the mentioned in comments SqlDataReader), it's relatively easy to wrap the data into an IAsyncEnumerable<T>:
async IAsyncEnumerable<(object first, object second, object product)> ExtractData(
SqlDataReader reader)
{
while (await reader.ReadAsync())
yield return (reader[0], reader[1], reader[2]);
}
and use it:
Task<string> Stringify(SqlDataReader reader) =>
StringEx.JoinAsync(
", ",
ExtractData(reader).Select(x => $"{x.first} * {x.second} = {x.product}"));
In order to use Select, you'll need to use nuget package System.Interactive.Async. Here you can find a compilable example.
How about this..
string str = "The quick brown fox jumps over the lazy dog,";
StringBuilder sb = new StringBuilder(str);
sb.Remove(str.Length - 1, 1);
Use the following after the loop.
.TrimEnd(',')
or simply change to
string commaSeparatedList = input.Aggregate((a, x) => a + ", " + x)
I prefer manipulating the length of the stringbuilder:
data.Length = data.Length - 1;
I recommend, you change your loop algorithm:
Add the comma not AFTER the item, but BEFORE
Use a boolean variable, that starts with false, do suppress the first comma
Set this boolean variable to true after testing it
You should use the string.Join method to turn a collection of items into a comma delimited string. It will ensure that there is no leading or trailing comma, as well as ensure the string is constructed efficiently (without unnecessary intermediate strings).
The most simple way would be to use the Join() method:
public static void Trail()
{
var list = new List<string> { "lala", "lulu", "lele" };
var data = string.Join(",", list);
}
If you really need the StringBuilder, trim the end comma after the loop:
data.ToString().TrimEnd(',');
Yes, convert it to a string once the loop is done:
String str = data.ToString().TrimEnd(',');
You have two options. First one is very easy use Remove method it is quite effective. Second way is to use ToString with start index and end index (MSDN documentation)
Similar SO question here.
I liked the using a StringBuilder extension method.
RemoveLast Method
Gotcha!!
Most of the answers on this thread won't work if you use AppendLine like below:
var builder = new StringBuilder();
builder.AppendLine("One,");
builder.Length--; // Won't work
Console.Write(builder.ToString());
builder = new StringBuilder();
builder.AppendLine("One,");
builder.Length += -1; // Won't work
Console.Write(builder.ToString());
builder = new StringBuilder();
builder.AppendLine("One,");
Console.Write(builder.TrimEnd(',')); // Won't work
Fiddle Me
WHY??? #(&**(&#!!
The issue is simple but took me a while to figure it out: Because there are 2 more invisible characters at the end CR and LF (Carriage Return and Line Feed). Therefore, you need to take away 3 last characters:
var builder = new StringBuilder();
builder.AppendLine("One,");
builder.Length -= 3; // This will work
Console.WriteLine(builder.ToString());
In Conclusion
Use Length-- or Length -= 1 if the last method you called was Append. Use Length =- 3 if you the last method you called AppendLine.
Simply shortens the stringbuilder length by 1;
StringBuilder sb = new StringBuilder();
sb.Length--;
i know this is not the effective way as it translates to sb = sb-1;
Alternative Effective solution
sb.Remove(starting_index, how_many_character_to_delete);
for our case it would be
sb.Remove(sb.length-1,1)

send a String array as parameter to a function

I have a function in a class called Function, like below:
public int SearchedRecords(String [] recs)
{
int counter = 0;
String pat = "-----";
String[] records = recs;
foreach (String line in records)
{
if (line.Contains(pat) == true)
{
counter++;
}
}
return counter;
}
And I am calling this method from my main class this way:
String [] file = File.ReadAllLines("C:/Users.../results.txt");
int counter = Function.SearchedRecords( []file);
But I get an error saying:
;expected
What is wrong?
Another question: The function above is counting from a file all the lines with the pattern ----- in them (even if with more dashes, or if the line has some chars before or after the dashes). Am I right?
It's something like the patterns in Java so maybe there is an other way.
Can you enlighten me?
Remove the [] from your parameter.
e.g.
int counter = Function.SearchedRecords(file);
And yes, your assumption about the behavior of the Contains method is correct - you'll match any line containing five consecutive dashes, regardless of what characters are before or after them.
If you want to parse for exactly five dashes, with nothing before or after them I suggest looking into the RegEx class (regular expressions).
Change
int counter = Function.SearchedRecords( []file);
to
int counter = Function.SearchedRecords(file);
and yes, this will work, for that string.
However Contains is case sensitive, if you were matching on a name, or another string with alphabetic characters, the case would have to be identical to match e.g. line.Contains("Binary Worrier") will not match a string "Hello binary worrier".
Also, reading the entire file into memory is fine if you know that the file will always be small, this method gets less efficient the larger the file.
Better to always use something like System.IO.StreamReader or System.IO.File.ReadLines (available in .Net 4 and later), these allow you to consume the file one line at a time. e.g.
using (var reader = new System.IO.StreamReader("MyFile.txt"))
{
while(!reader.EndOfStream)
{
string line = reader.ReadLine();
if (line.Contains(pattern))
counter++;
}
}
Change it to
int counter = Function.SearchedRecords(file);
Remove '[]' from a method call. Yes, your function seems to count what you want.
First of all you need to create an instance of function class and then run the function. Hope following code helps
Function fb = new Function();
int counter = fb.SearchedRecords(file);
Right now, you are using SearchRecords as an static function of a static class which doesn't require instantiation.
You can do this in a shorter way using LINQ:
int counter = file.Count(line => line.Contains("-----"));

Using string.Substring() as part of a chain

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('_', ' ');

Categories

Resources