string nr = "42245555" //just an example number
string expression = "{5}{6}/{7}{8}";
string res = String.Format(expression, new string[] {
nr[0].ToString(),nr[1].ToString(),
nr[2].ToString(), nr[3].ToString(),
nr[4].ToString(), nr[5].ToString(),
nr[6].ToString(), nr[7].ToString()
});
Why is this not working and how can I solve it?
I want expression to be either "{5}{6}/{7}{8}" or "{0}{3}/{7}{1}" or whatever the user wants.
You must supply at least the same number of parameters (or an array with at least the same number of elements) as the highest placeholder value plus one (placeholder values are zero indexed)
Max placeholder value {3}, you must supply at least four additional parameters.
Try this:
string res = String.Format(expression,
nr[0], nr[1],
nr[2], nr[3],
nr[4], nr[5],
nr[6], nr[7]);
Note that I took out new string[] { ... } I also took out all the ToString() because they are not required.
The relevant overload of Format is:
public static string Format(string format, params Object[] args)
This means you can either call it like this:
Format("...",new object[]{...})//Each array element is used
Or with the objects directly as parameters:
Format("...",object1, object2,...)//the objects are used
Unlike what I originally thought, a string[] does indeed go into the first variant of this code. This is due to array covariance in C#/.net which allows a string[] to be implicitly converted to a object[].
string.Format("{0} {1}",new string[]{"A","B"})
prints A B.
On the other hand if you try similar code with a int[] it won't work:
string.Format("{0} {1}",new int[]{1,2})
Will throw an exception because it goes into the second variation, and thus only a single parameter of type int[] is seen by string.Format. This difference is because array covariance only works on arrays with members that are a reference type like string and not a value type like int. This means int[] is not implicitly convertible to object[].
So the problem with your original code is probably just that you used the index {8} which is out of range.
The parameters in expression must start from "{0}" and the array must contain the same number of parameters as the expression and it must be an array of objects : new object[]{...
Your parameters are numbered 0..7, easy to read back. Yet you use {8} : Index out of Range
You don't need the new string[] { } around the parameters. It is allowed though.
without the new string[] { } you don't need the .ToString() calls either.
IF ur user wants {5}{6}/{7}{8} , then ur code will be:
String.Format("{0}{1}/{2}{3}",nr[4],nr[5],nr[6],nr[7]);
ur indexes in the expression must always start with 0..In my example if u want to display this for strings.. u start by 0,1,2,3.. 0 for nr[4], 1 for nr[5], 2 for nr[6], 3 for nr[7], etc..
You have to use:
nr.Substring(...)
in String.Format([expression], [values]) expression is a string represent a string with placeholders while values are inserted in those placeholders.
updated
string nr = "42245555" //just an example number
string res = String.Format("{0}{1}/{2}{3}", new string[] {
nr[5].ToString(),nr[6].ToString(),
nr[7].ToString(), nr[8].ToString()
});
or
string res = String.Format("{0}{1}/{2}{3}", new string[] {
nr[0].ToString(),nr[3].ToString(),
nr[7].ToString(), nr[1].ToString()
});
Related
Currently I am trying to write something to take strings from a txt file and input them into an array. I was doing it by manually inputting them and using interpolated strings but that is becoming unfeasible now. I need to be able to change parts of the string depending on the result of a function, and on any given string there could 0 to any number of parts that need to be changed. I figured this would work in theory but that there had to be a better way:
public void formatStringInSentencesArray(int numOfArgs, int arrIndexToBeFormatted, UnityAction[] funcsToBePutIn)
{
if (numOfArgs == 1)
{
conversation[index].sentences[arrIndexToBeFormatted] = string.Format(conversation[index].sentences[arrIndexToBeFormatted], funcsToBePutIn[0]);
}
...
else if (numOfArgs == 5)
{
conversation[index].sentences[arrIndexToBeFormatted] = string.Format(conversation[index].sentences[arrIndexToBeFormatted], funcsToBePutIn[0], funcsToBePutIn[1], funcsToBePutIn[2], funcsToBePutIn[3], funcsToBePutIn[4]);
}
Is there any way I could go about doing this in a way that isn't just a hacked together bunch of ifs and else ifs? (This is all written in C# for a unity game btw)
Welcome to SO.
string.format already supports arrays. Is this what you're looking for?
var paramArray = new string[] { "a", "b", "c", "d", "e" };
var output = string.Format("{0} {1} {2} {3}", paramArray);
Based on your example, I'd probably replace your function with:
conversation[index].sentences[arrIndexToBeFormatted] = string.Format(conversation[index].sentences[arrIndexToBeFormatted], funcsToBePutIn);
By using the params keyword, you can specify a method parameter that takes a variable number of arguments. The parameter type must be a single-dimensional array.
No additional parameters are permitted after the params keyword in a method declaration, and only one params keyword is permitted in a method declaration.
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/params
The compiler will deal with turning that line of Arguments into a single array.
The String.Format() - and function that use it like Console.WriteLine() - use the params keyword. The main function behaves as if it does, but given that the data comes from the OS it is possible it is not using the keyword (making the array is somebody elses job).
I am new to c# programming and I recently bumped into one problem which looks pretty basic.I store the string value like SV_1 in the variable lastServiceNo and split it using Split function and the result is stored in string array called index.Basically index[1] has some numeric value bt as string. now I want to convert string into int. In the following code , it behaves as expected until parse function is encountered.I could not understand why does this parse function returning 0 as index[1] has some numeric value in it. Can somebody point the problem please??
public string GenerateServiceNo() {
DataAccessLayer.DataAccessLayer dlObj= new DataAccessLayer.DataAccessLayer();
string lastServiceNo = dlObj.GetLastServiceNo();
string[] index = lastServiceNo.Split('_');
int lastIndex = int.Parse(index[1]);
return "SV_"+(lastIndex++).ToString();
}
int.Parse(string s) throws an exception if the number is too bug in terms of data size or the string "s" is not in the correct numerical format.
The format that this method accepts is "[ws][sign]number[ws]" where:
[ws] is optional for one or more whitespace(" ")
[sign] is optional for "+" or "-"
Check here for the full reference.
Thus said, I can assure you that if int.Parse(index[1]) returns 0 then that means index[1] equals "[ws][sign]0[ws]" using the transcript above.
However, looking at your code, I can conclude that you're incrementing a local variable after assignment without using its incremented value afterwards. Perhaps you meant that this operation shouldn't be 0?
If that's the case then I believe this is what you're trying to achieve:
public string GenerateServiceNo()
{
DataAccessLayer.DataAccessLayer dlObj= new DataAccessLayer.DataAccessLayer();
string lastServiceNo = dlObj.GetLastServiceNo();
string[] index = lastServiceNo.Split('_');
int lastIndex = int.Parse(index[1]);
return string.Format("SV_{0}", ++lastIndex);
}
Assuming index[1] == "0", this method will now return "SV_1".
carry the code below where I embarked.
class readFile{
List<double> out1 = new List<double>();
List<double> out2 = new List<double>();
List<double> out3 = new List<double>();
public readFile()
{
}
public void aproCSV()
{
var reader = new StreamReader(File.OpenRead(#"C:\altraprova.csv"));
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
var values = line.Split(';');
out1.Add(values[0]);
out2.Add(values[1]);
out3.Add(values[2]);
}
}
}
Allow me to explain my intent ....
I open my csv file
the goal is to read the second column and insert it into a list of type double and then get the value MAX.
If you use lists of type string not get erors .... but since the values contain only numbers you are signed semicolon, then I need to use the type double.. using the double type get the following error:
error 5 The best match of the overloaded method for
'System.Collections.Generic.List <double> .Add (double)' has some
invalid arguments
Split() returns a string[] and your lists are of type List<double> which means you need to parse the strings into doubles like the following:
double value1 = double.Parse(values[0]); etc
then add them to your list: out1.Add(value1);
Do be aware that you have no error handling so if the value is not a double, the code will still throw an exception.
CSV are surprisingly not so straightforward to parse, there are a lot of special cases which you have to take into consideration. For example, if your data would contain the "separation character" you'd need to put the data between quotes ("). If he contains quotes, then you have to escape them with a backslash (\) (or doubling them, I'm not sure).
So, except if you know the data you're going to be importing and are sure that those case won't happen, a simple "split" won't be sufficient.
I really recommend using an existing parser to help you on this task. I've used CsvHelper with success. It's a nice library and quite easy to use.
You need to do some parsing, because a generic list only accepts elements of the given type (double in your case):
var line = reader.ReadLine();
var values = line.Split(';');
out1.Add(double.Parse(values[0]));
out2.Add(double.Parse(values[1]));
out3.Add(double.Parse(values[2]));
This is the quick and dirty trick, you should use double.TryParse
for safety because maybe not everything you get is a double.
From you code I suppose the you need to get the max from list out2 (your second column). For this, use List.Max Method
I am prompting the user to enter their first middle and last name in one prompt.
So if they type for example John Ronald Doe, how can I take those values from that one string and assign them to fname, mname, lname, to create a person constructor that takes these values.
Basically my question is how to take multiple values in one prompt for a user and then assign them to different variables for a constructor.
Thank you!
Just grab the line then split on white spaces. You'll have to do some input validation to make sure they actually enter fName mName lName but I'll leave that to you because what you do is dependent on how robust the application needs to be. By that I mean, what happens if the user only enters two words? Do you just assume it's first and last name and set their middle name to String.Empty ? What happens if they enter 4 or 5 words?
string[] tokens = Console.ReadLine().Split(' ');
if (tokens.Length == 3)
{
// do assignment
}
With regard to your comment;
That is more or less correct. Really what's happening is ReadLine() is returning a string. I'm just calling Split(' ') directly on that result. You could break it into two lines if you'd like but there's no reason to. Split(char delimiter) is an instance method in the String class. It takes a char and returns an array of strings. I'm using tokens because it's kind of a common term. The line is build of three tokens, the first, middle, and last names. It's important to understand that I am not adding anything to an array, Split(' ') is returning an array. string[] tokens is just declaring a reference of type string[], I don't have to worry about the size or anything like that.
An example to get an array of ints from the input. Note, if any of the input is not a valid integer this will throw an exception.
int[] myInts = Console.ReadLine.Split(' ').Select(x => int.Parse(x)).ToArray();
In this example I'm using LINQ on the result of the split. Split returns a string array. Select iterates over that array and applies the lambda expression I pass it to each of it's values. It's best to think of x as the current value. The Select call here is roughly equivalent to;
List<int> myInts = new List<int>();
foreach (string s in tokens)
{
myInts.Add(int.Parse(s));
}
int[] myIntArray = myInts.ToArray();
If you can't trust the user input you should use TryParse. I don't know if you can use that as part of a lambda expression (it wouldn't surprise me if you could but it seems like a pain in the ass so I wouldn't bother) instead I'd do;
List<int> myInts = new List<int>();
int temp;
foreach (string s in tokens)
{
if (int.TryParse(s, temp)
myInts.Add(temp);
else
// the input wasn't an int
}
int[] myIntArray = myInts.ToArray();
I am working on a file parser, and this bit of code is not giving me what I want. Before I go any farther, I should mention that I did not write this program, I am only editing the source to fix this specific problem. Also, I can compile the code, so that is not a problem (you know how downloaded programs always have compile errors). Here's the code.
case EsfValueType.Binary4E: //System.String[]
{
int size = (int)(this.reader.ReadUInt32() - ((uint)this.reader.BaseStream.Position));
var strings = new string[size / 4];
for (int i = 0; i < size / 4; i++)
strings[i] = this.stringValuesUTF16[this.reader.ReadUInt32()];
esfValue.Value = strings.ToString();
break;
}
Now, I added the .ToString(); part to the above line, but it made no difference. The problem is that esfValue.Value ends up with System.String[] as it's value, and I want the value of the System.String object. If you can make sense out of this and tell me what is wrong, it would be appreciated.
The program name is ESF Editor 1.4.8.0.
case EsfValueType.Binary4E: //System.String[]
{
int size = (int)(this.reader.ReadUInt32() - ((uint)this.reader.BaseStream.Position));
var strings = new StringBuilder();
for (int i = 0; i < size / 4; i++)
{
strings.Append(this.stringValuesUTF16[this.reader.ReadUInt32()]); //or AppendLine, depending on what you need
}
esfValue.Value = strings.ToString();
break;
}
The strings variable is an array of strings - the Array class does not override the default ToString() implementation which returns the type of the object.
You need to concatenate all the strings in the array - either looping and concatenating or using LINQ and assign the resulting string to esfValue.Value. Of course, this assumes you want the values all in one string, one after the other.
Your issue is that strings isn't a single string, its an array of strings. As a result your call to ToString is calling Object.ToString(), which returns the type of the object.
Maybe you want something like
esfValue.Value = strings.Aggregate((acc, next) => acc + next)
which will simply concatenate all the strings together.
When you do a .ToString() on a class that doesn't override the .ToString() base method to return a custom string (which string[] doesn't), you're always going to get the type's namespace/class as the result.
Arrays, in and of themselves, don't have values. What value are you trying to get? Are you trying to join the array into a single, character-delimited string? If so, this would work:
esfValue.Value = string.Join(",", strings);
Just replace the , with whatever character you want to delimit the array with.
I think you just need to join the string values contained in the string array. In order to do so, you need to call String.Join and pass the string separator and the string array. It returns a single System.String.