Return syntax little strange [duplicate] - c#

This question already has answers here:
What is recursion and when should I use it?
(40 answers)
Closed 4 years ago.
I coming back to C# programming after some years of HTML/ASP.
I came across these lines and cannot find what it does.
It is a method in a class:
private string PeekNext()
{
if (pos < 0)
// pos < 0 indicates that there are no more tokens
return null;
if (pos < tokens.Length)
{
if (tokens[pos].Length == 0)
{
++pos;
return PeekNext();
}
return tokens[pos];
}
string line = reader.ReadLine();
if (line == null)
{
// There is no more data to read
pos = -1;
return null;
}
// Split the line that was read on white space characters
tokens = line.Split(null);
pos = 0;
return PeekNext();
}
Is it calling itself until some of the other Returns happens?
What is happening here, never seen a method returning itself!?
What is Returned, empty string or what...?
Or maybe I just missed it before.
Maybe simple but puzzles me.

private string PeekNext()
{
if (pos < 0)
// pos < 0 indicates that there are no more tokens
return null;
if (pos < tokens.Length)
{
if (tokens[pos].Length == 0)
{
++pos;
return PeekNext();
}
return tokens[pos];
}
string line = reader.ReadLine();
if (line == null)
{
// There is no more data to read
pos = -1;
return null;
}
// Split the line that was read on white space characters
tokens = line.Split(null);
pos = 0;
return PeekNext();

Notwithstanding the fact that the method depends on external (class) variables, and should probably be refactored to take its dependencies as parameters, a non-recursive version could look as follows:
private string PeekNext()
{
while (pos >= 0)
{
if (pos < tokens.Length)
{
if (tokens[pos].Length == 0)
{
++pos;
continue;
}
return tokens[pos];
}
string line = reader.ReadLine();
if (line == null)
{
// There is no more data to read
pos = -1;
return null;
}
// Split the line that was read on white space characters
tokens = line.Split(null);
pos = 0;
}
// pos < 0 indicates that there are no more tokens
return null;
}

Related

Assign variable and check it within an IF evaluation

I doubt this can be done but I'll ask anyway since it would make my code much more readable.
I have to control a large string for various substrings and elaborate it in different ways depending on the substring found.
At the moment I have a nested if like
position = mystring.IndexOf("my substring")
if (position>0)
{
position = mystring.IndexOf("somestring", position);
[...]
}
else
{
position = mystring.IndexOf("my substring2")
if (position>0)
{
position = mystring.IndexOf("somestring2", position);
[...]
}
else {...}
}
The only other way I can think of doing this is double casting the IndexOf function:
if (mystring.IndexOf("my substring")>0)
{
position = mystring.IndexOf("somestring", mystring.IndexOf("my substring"));
[...]
}
else if (mystring.IndexOf(mysubstring2)>0)
{
position = mystring.IndexOf("somestring2", mystring.IndexOf("my substring2"));
[...]
}
else {...}
Is there a way to check the IndexOf() result and assign it to a variable all within the if() statement?
Something on the line of
if ((position = mystring.IndexOf("my substring")) AndAlso position > 0) { ... }
or any tip on having such a piece of code handled better?
Yes you can do it, like so:
var myString = "Hello World";
int pos;
if ((pos = myString.IndexOf("World")) >= 0)
{
Console.WriteLine(pos); // prints 6
}
else if ((pos = myString.IndexOf("Some Other Substring")) >= 0)
{
// Do whatever
}
Note that I'm using myString.IndexOf(...) >= 0 as the index of the substring could be 0 (i.e starting at the first character), and the IndexOf method returns -1 if none was found
But you could rather just use string.Contains like so:
var myString = "Hello World";
if (myString.Contains("World"))
{
// Do whatever
}
else if (myString.Contains("Some Other Substring"))
{
// Do whatever
}
This is better if you don't explicitly need the location of the substring, but if you do, use the first one
Technically, you can put it as
int position;
if ((position = mystring.IndexOf("my substring")) > 0)
{
// Note, that you should use position + "my substring".Length if
// "somestring" can't be part of previous match
position = mystring.IndexOf("somestring", position);
[...]
}
else if ((position = mystring.IndexOf(mysubstring2)) > 0)
{
position = mystring.IndexOf("somestring2", position);
[...]
}
else {...}
However, I suggest extracting a method:
private static bool FindMany(string source, out int lastIndex, params string[] toFind) {
if (null == toFind)
throw new ArgumentNullException(nameof(toFind));
lastIndex = -1;
int result = -1;
if (string.IsNullOrEmpty(source))
return false;
int index = 0;
for (int i = 0; i < toFind.Length; ++i) {
result = source.IndexOf(toFind[i], index);
index += toFind[i].Length;
if (index < 0)
return false;
}
lastIndex = result;
return true;
}
Which you can use as
int position;
if (FindMany(mystring, out position, "my substring", "somestring") {
// "my substring" found
if (position >= 0) {
// "somestring" is found as well; its index - position
...
}
else {
// only "my substring" has been found
}
}
else if (FindMany(mystring, out position, "my substring2", "somestring2") {
// "my substring2" found
if (position >= 0) {
// "somestring2" is found
...
}
}
Use Contains() and, in addition, use IndexOf()separately if you really need to have a position by some reason. if (mystring.Contains("my substring")) { ... }
this does sound like a job for regex with positive lookbehind:
a positive lookbehind makes sure that the string inside (?<=) exists prior to the other string
Together with a TryGet..approach with an out parameter it can almost become a one liner.
However, Dmitrys solution is a tad more future proof, since it accepts multiple input strings to search for. Building that regex could prove unmaintainable
https://dotnetfiddle.net/D5WFyx
using System;
using System.Text.RegularExpressions;
public static void Main()
{
string input = "here is my substring and then somestring";
int position;
if (TryGetIndex(input, "(?<=my substring.*)somestring", out position)){
Console.WriteLine($"somestring index: {position}");
}
else if (TryGetIndex(input, "(?<=other substring.*)otherstring", out position)) {
Console.WriteLine($"otherstring index: {position}");
}
bool TryGetIndex(string input, string pattern, out int position){
var match = Regex.Match(input, pattern);
if (match.Success){
position = match.Index;
return true;
}
position = -1;
return false;
}
}

StringBuilder not appending int to beginning of string unless 0 or 10

I have a bowling game that takes the list of bowls and then runs them through this code to produce a string that goes through the frames on the UI. If the user bowls a gutter (0) or strike (10) the code works fine. However, if it is between 1 and 9, it fails to produce a string. Why is this? I've searched and tried many other ways to do this, but this seems to be the only way it will work.
public static StringBuilder FormatRolls (List<int> rolls) {
StringBuilder output = new StringBuilder();
for (int i=0; i < rolls.Count; i++) {
if (rolls.Count >= 19 && rolls[i] == 10) { //Bonus End-Frame Strike
output.Append ("X");
} else if (rolls[i] == 0) { //Gutter
output.Append ("-");
} else if (rolls[i-1] + rolls[i] == 10 && rolls.Count > 1) { //Spare
output.Append ("/");
} else if (rolls[i] == 10 && rolls[i+1] == 0) { //Strike
output.Append ("X");
} else { //Normal bowls 1-9
output.Append (rolls[i].ToString());
}
}
output.ToString();
return output;
}
This is the code that then writes to all of the frames:
public void FillRolls (List<int> rolls) {
StringBuilder scoresString = FormatRolls(rolls);
for (int i=0; i<scoresString.Length; i++) {
frameText[i].text = scoresString[i].ToString();
}
}
Any help is greatly appreciated, I've been stuck for DAYS trying to get this to work...
output.ToString(); is a pure function and you are not using its return value (so, you are converting to a string, and then throwing that string away without using/storing/returning it). I guess you really want to return the fully built and formatted string, not the StringBuilder instance. Use:
return output.ToString();
That said, other codepaths should not produce a value either.
After rolling through all the comments and suggestions from others, I took away the try-catch section that blocked me from seeing past my catch error. Then, added debug.log statements to help find the correct position and used Unity's built-in errors to find this wasn't the string's fault at all. It was trying to find an index rolls[i]-1 that didn't exist. After a few attempts I found that if I changed the else if (rolls[i-1] + rolls[i] == 10 && rolls.Count > 1) to a nested if statement and used the output.Length instead of rolls.Count it would no longer return an error. Thank you everyone who tried to help me solve this, you pointed me in the right direction and really got me thinking! Here is the finished code:
public static string FormatRolls (List<int> rolls) {
StringBuilder output = new StringBuilder();
for (int i=0; i < rolls.Count; i++) {
if (rolls.Count >= 19 && rolls[i] == 10) { //Bonus End-Frame Strike
output.Append ("X");
} else if (rolls[i] == 0) { //Gutter
output.Append ("-");
} else if (rolls[i] == 10 && output.Length % 2 == 0) { //Strike
output.Append (" X");
} else if (output.Length >= 1 && output.Length % 2 != 0) { //Spare
if (rolls[i-1] + rolls[i] == 10) {
output.Append ("/");
}
} else { //Normal bowls 1-9
output.Append (rolls[i]);
}
}
return output.ToString();
}

Writing a recursive function in C#

I need to write a function which verifies parentheses are balanced in a string. Each open parentheses should have a corresponding close parentheses and they should correspond correctly.
For example, the function should return true for the following strings:
(if (any? x) sum (/1 x))
I said (it's not (yet) complete). (she didn't listen)
The function should return false for the following strings:
:-)
())(
OPTIONAL BONUS
Implement the solution as a recursive function with no mutation / side-effects.
Can you please help me out in writing using C# because I'm new to .NET technologies.
Thanks.
Here's what I've tried so far. It works for sending parameters as open and close brackets, but I'm confused with just passing a string... and also I should not use stack.
private static bool Balanced(string input, string openParenthesis, string closedParenthesis)
{
try
{
if (input.Length > 0)
{
//Obtain first character
string firstString = input.Substring(0, 1);
//Check if it is open parenthesis
//If it is open parenthesis push it to stack
//If it is closed parenthesis pop it
if (firstString == openParenthesis)
stack.Push(firstString);
else if (firstString == closedParenthesis)
stack.Pop();
//In next iteration, chop off first string so that it can iterate recursively through rest of the string
input = input.Substring(1, input.Length - 1);
Balanced(input, openParenthesis, closedParenthesis); //this call makes the function recursive
}
if (stack.Count == 0 && !exception)
isBalanced = true;
}
catch (Exception ex)
{
exception = true;
}
return isBalanced;
}
You don't need to use any recursion method for such a simple requirement, just try this simple method and it works like a charm:
public bool AreParenthesesBalanced(string input) {
int k = 0;
for (int i = 0; i < input.Length; i++) {
if (input[i] == '(') k++;
else if (input[i] == ')'){
if(k > 0) k--;
else return false;
}
}
return k == 0;
}
I have used the startIndex and increment with each recursive call
List<string> likeStack = new List<string>();
private static bool Balanced(string input, string openParenthesis, string closedParenthesis , int startIndex)
{
try
{
if (startIndex < input.Length)
{
//Obtain first character
string firstString = input.Substring(startIndex, 1);
//Check if it is open parenthesis
//If it is open parenthesis push it to stack
//If it is closed parenthesis pop it
if (firstString == openParenthesis)
likeStack.Add(firstString);
else if (firstString == closedParenthesis)
likeStack.RemoveAt(likeStack.Count -1);
//In next iteration, chop off first string so that it can iterate recursively through rest of the string
Balanced(input, openParenthesis, closedParenthesis , startIndex + 1); //this call makes the function recursive
}
if (likeStack.Count == 0 && !exception)
isBalanced = true;
}
catch (Exception ex)
{
exception = true;
}
return isBalanced;
}
How's this recursive version?
public static bool Balanced(string s)
{
var ix = -1;
return Balanced(s, false, ref ix);
}
private static bool Balanced(string s, bool inParens, ref int ix)
{
ix++;
while (ix < s.Length)
{
switch (s[ix++])
{
case '(':
if (!Balanced(s, true, ref ix))
return false;
break;
case ')':
return inParens;
}
}
return !inParens;
}

How can I do take a substring and length of a string in C# if that string might be a null?

I have the following strings:
var temp = null;
var temp = "";
var temp = "12345678";
var temp = "1234567890";
What I need to do is if have a function that will give me the last four digits of the input variable if the input variable is 8 or 10 characters long. Otherwise I need it to return "";
Is there an easy way I can do this in C#. I am just not sure how to deal with null because if I get the length of null then I think that will give me an error.
int length = (temp ?? "").Length;
string subString = "";
if(length == 8 || length == 10)
{
subString = temp.Substring(length - 4);
}
You can use IsNullOrEmpty, As if string is null or Empty then substring is not possible.
if (!String.IsNullOrEmpty(str) && (str.Length == 8 || str.Length == 10))
{
string substr = str.Substring(str.Length-4);
}
Try this
string YourFunctionName(string input)
{
string rVal = "";
if (string.IsNullOrEmpty(input))
return rVal;
if (input.Length == 8 || input.Length == 10)
rVal = input.Substring(input.Length - 4);
return rVal;
}
I would likely write it like this, if writing a function:
string GiveMeABetterName (string input) {
if (input != null
&& (input.Length == 8 || input.Length == 10)) {
return input.Substring(input.Length - 4);
} else {
return "";
}
}
As can be seen by all the answers, there is multiple ways to accomplish this.

Unable to find csv file on ASP.NET

Anyone who knows how to solve this error please help me. Below is my code for reading the csv file. When I tried to upload it showed me *Server Error in '/' Application. Could not find file 'C:/...csv * Im a beginner in c#.
ReadCSV
string filename = FileUpload1.PostedFile.FileName;
using (CsvFileReader reader = new CsvFileReader(filename))
{
CsvRow row = new CsvRow();
while (reader.ReadRow(row))
{
foreach (string s in row)
{
Console.Write(s);
Console.Write(" ");
TextBox1.Text += s;
}
Console.WriteLine();
}
}
CSVClass
public class CsvFileReader : StreamReader
{
public CsvFileReader(Stream stream)
: base(stream)
{
}
public CsvFileReader(string filename): base(filename)
{
}
/// <summary>
/// Reads a row of data from a CSV file
/// </summary>
/// <param name="row"></param>
/// <returns></returns>
public bool ReadRow(CsvRow row)
{
row.LineText = ReadLine();
if (String.IsNullOrEmpty(row.LineText))
return false;
int pos = 0;
int rows = 0;
while (pos < row.LineText.Length)
{
string value;
// Special handling for quoted field
if (row.LineText[pos] == '"')
{
// Skip initial quote
pos++;
// Parse quoted value
int start = pos;
while (pos < row.LineText.Length)
{
// Test for quote character
if (row.LineText[pos] == '"')
{
// Found one
pos++;
// If two quotes together, keep one
// Otherwise, indicates end of value
if (pos >= row.LineText.Length || row.LineText[pos] != '"')
{
pos--;
break;
}
}
pos++;
}
value = row.LineText.Substring(start, pos - start);
value = value.Replace("\"\"", "\"");
}
else
{
// Parse unquoted value
int start = pos;
while (pos < row.LineText.Length && row.LineText[pos] != ',')
pos++;
value = row.LineText.Substring(start, pos - start);
}
// Add field to list
if (rows < row.Count)
row[rows] = value;
else
row.Add(value);
rows++;
// Eat up to and including next comma
while (pos < row.LineText.Length && row.LineText[pos] != ',')
pos++;
if (pos < row.LineText.Length)
pos++;
}
// Delete any unused items
while (row.Count > rows)
row.RemoveAt(rows);
// Return true if any columns read
return (row.Count > 0);
}
}
FileUpload1.PostedFile.FileName is the filename from your client/browser - it does not contain a path...
You either use FileUpload1.PostedFile.InputStream to access it
using (CsvFileReader reader = new CsvFileReader(FileUpload1.PostedFile.InputStream))
OR you first save it to disk (anywhere you have needed permissions) via FileUpload1.PostedFile.SaveAs and then access that file.
You need to save the file that is being uploaded to disk first. Something like this:
string fileSavePath= Sever.MapPath("/files/" + FileUpload1.PostedFile.FileName);
FileUpload1.SaveAs(fileSavePath);
using (CsvFileReader reader = new CsvFileReader(fileSavePath))
....
Haven't tested this code, but should give you a starting point.

Categories