I've got the following Problem:
I want to take parts of a string into an array. So far no problem (splitstring),
but, I can't use splitstring because it takes my operators out.
Explained on an example:
Following string: "47-62*5141"
I need it like this: {"47", "-", "62", "*", "5141"}
If you could give me a code example, I would be very pleased!
Just split according to the word boundary which exist at the middle.
Regex.Split(string, #"(?!^)\b(?!$)");
DEMO
I've made a little uglycode. But it works.
class Program
{
static void Main(string[] args)
{
var text = "47-62**5141";
var splittedText = text.SplitAndKeepSeparator('-', '*');
foreach (var part in splittedText)
{
Console.WriteLine(part);
}
Console.ReadLine();
}
}
public static class StringExtensions
{
public static IEnumerable<string> SplitAndKeepSeparator(this string s, params char[] seperators)
{
var parts = s.Split(seperators, StringSplitOptions.None);
var partIndex = 0;
var isPart = true;
var indexInText = 0;
while (partIndex < parts.Length)
{
if (isPart)
{
var partToReturn = parts[partIndex];
if (string.IsNullOrEmpty(partToReturn))
{
partToReturn = s[indexInText].ToString();
}
else
{
isPart = false;
}
indexInText += partToReturn.Length;
partIndex++;
yield return partToReturn;
}
else
{
var currentSeparator = s[indexInText];
indexInText++;
isPart = true;
yield return currentSeparator.ToString();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string[] parts = new string[100];
var text = "47-62*5141";
int i = 0;
var splittedText = text.SplitAndKeepSeparator('-', '*', '+', '/');
foreach (var part in splittedText)
{
parts[i] = part;
i++;
}
Console.ReadLine();
Console.WriteLine(parts[0]);
Console.WriteLine(parts[1]);
Console.WriteLine(parts[2]);
Console.WriteLine(parts[3]);
Console.ReadLine();
}
}
}
public static class StringExtensions
{
public static IEnumerable<string> SplitAndKeepSeparator(this string s, params char[] seperators)
{
var parts = s.Split(seperators, StringSplitOptions.None);
var partIndex = 0;
var isPart = true;
var indexInText = 0;
while (partIndex < parts.Length)
{
if (isPart)
{
var partToReturn = parts[partIndex];
if (string.IsNullOrEmpty(partToReturn))
{
partToReturn = s[indexInText].ToString();
}
else
{
isPart = false;
}
indexInText += partToReturn.Length;
partIndex++;
yield return partToReturn;
}
else
{
var currentSeparator = s[indexInText];
indexInText++;
isPart = true;
yield return currentSeparator.ToString();
}
}
}
}
Related
My problem is probably stupid, but I can't figure out the solution by myself, so I hope someone here can help me.
I am trying to make a dll file for hosting a server on the localhost. I thought I did everything right, but I receive this error:
System.IndexOutOfRangeException: Index was outside the bounds of the array.
at minihttpc.Requests.HttpRequest.ParseHeaders(String[] requestLine) in C:\Users\deqnb\OneDrive\minihttpc\minihttpc\Requests\HttpRequest.cs:line 87
at minihttpc.Requests.HttpRequest.ParseRequest(String requestString) in C:\Users\deqnb\OneDrive\minihttpc\minihttpc\Requests\HttpRequest.cs:line 44
at minihttpc.Requests.HttpRequest..ctor(String requestString) in C:\Users\deqnb\OneDrive\minihttpc\minihttpc\Requests\HttpRequest.cs:line 21
at MiniServerHTTP.WebServer.ConnectionHandler.ReadRequest() in C:\Users\deqnb\OneDrive\minihttpc\MiniServerHTTP.WebServer\ConnectionHandler.cs:line 80
at MiniServerHTTP.WebServer.ConnectionHandler.ProcessRequest() in C:\Users\deqnb\OneDrive\minihttpc\MiniServerHTTP.WebServer\ConnectionHandler.cs:line 28
Here is my code - HttpRequest.cs:
using minihttpc.Common.CoreValidator;
using minihttpc.Common.GlobalConstants;
using minihttpc.Headers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace minihttpc.Requests
{
public class HttpRequest:IHttpRequest
{
public HttpRequest(string requestString)
{
CoreValidator.ThrowIfNullOrEmpty(requestString, nameof(requestString));
this.FormData = new Dictionary<string, object>();
this.QueryData = new Dictionary<string, object>();
this.Headers = new HttpHeaderCollection();
this.ParseRequest(requestString);
}
public string Path { get; private set; }
public string Url { get; private set; }
public Dictionary<string,object>FormData { get; }
public Dictionary<string, object> QueryData { get; }
public IHttpHeaderCollection Headers { get; private set; }
public HttpRequestMethod RequestMethod { get; private set; }
public void ParseRequest(string requestString)
{
string[] splitRequestContent = requestString.Split(new[] {
GlobalConstants.HttpNewLine }, StringSplitOptions.None);
string[] requestLine = splitRequestContent[0].Trim().Split(new[]
{ ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (!this.IsValidReqiestLine(requestLine))
{
throw new BadRequestException();
}
this.ParseRequestMethod(requestLine);
this.ParseRequestUrl(requestLine);
this.ParseRequestPath();
this.ParseHeaders(splitRequestContent.Skip(1).ToArray());
//this.ParseRequestQueryParameters();
this.ParseRequestParameters(splitRequestContent[splitRequestContent.Length - 1]);
}
bool IsValidRequestLine(string[] requestLine)
{
if (requestLine.Count() != 3 && requestLine[2] != "HTTP/1.1")
{
return false;
}
else
{
return true;
}
}
void ParseRequestMethod(string[] requestLine)
{
switch (requestLine[0])
{
case "GET": RequestMethod = HttpRequestMethod.Get; break;
case "POST": RequestMethod = HttpRequestMethod.Post; break;
case "PUT": RequestMethod = HttpRequestMethod.Put; break;
case "DELETE": RequestMethod = HttpRequestMethod.Delete; break;
}
}
void ParseRequestUrl(string [] requestLine)
{
this.Url = requestLine[1];
}
void ParseRequestPath()
{
this.Path = this.Url.Split("?").Take(1).First().ToString();
}
void ParseHeaders(string [] requestLine)
{
foreach(var line in requestLine)
{
Console.WriteLine(line); //a lot of info about the req
if (line == GlobalConstants.HttpNewLine) break;
string[] header = line.Split(' ').ToArray();
//Console.WriteLine(header[1]);
Headers.AddHeader(new HttpHeader(header[0],
header[1]));//seems fine //line 87
}
if (Headers.ContainsHeader("host"))
{
throw new BadRequestException();
}
}
void ParseRequestQueryParameters()
{
if (!(this.Url.Split('?').Length > 1)) return;
this.Url.Split('?', '#')[1].Split('&').Select(plainQueryParameter =>
plainQueryParameter.Split());//not finished !!!!
}
void ParseFormDataParameters(string formData)
{
if (!string.IsNullOrEmpty(formData))
{
formData.Split('&').Select(plainQueryParameter =>
plainQueryParameter.Split('=')).ToList().ForEach(queryParameterKeyValue =>
this.FormData.Add(queryParameterKeyValue[0],
queryParameterKeyValue[1]));
}
}
void ParseRequestParameters(string formData)//not being called
{
ParseRequestQueryParameters();
ParseFormDataParameters(formData);
}
}
}
ConnectionHandler.cs:
using minihttpc.Common.CoreValidator;
using minihttpc.Requests;
using MiniServerHTTP.WebServer.Results;
using MiniServerHTTP.WebServer.Routing;
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace MiniServerHTTP.WebServer
{
public class ConnectionHandler
{
private readonly Socket client;
private readonly IServerRoutingTable table;
public ConnectionHandler(Socket client, IServerRoutingTable table)
{
CoreValidator.ThrowIfNull(client, nameof(client));
CoreValidator.ThrowIfNull(client, nameof(client));
this.client = client;
this.table = table;
}
public async Task ProcessRequest()
{
try
{
var httpRequest = await this.ReadRequest();
if (httpRequest != null)
{
Console.WriteLine($"Processing: {httpRequest.RequestMethod} {httpRequest.Path}...");
var httpResponse = this.HandleRequest((IHttpRequest)httpRequest);
this.ProcessResponse(httpResponse);
}
}
catch (BadRequestException e)//400
{
this.ProcessResponse(new TextResult(e.ToString(),
HttpResponseStatusCode.BadRequest));
}
catch (Exception e)//500
{
this.ProcessResponse(new TextResult(e.ToString(),
HttpResponseStatusCode.InternalServerError));
}
this.client.Shutdown(SocketShutdown.Both);
}
private async Task ProcessResponse(IHttpResponse httpResponse)
{
byte[] byteSegments = httpResponse.GetBytes();
await this.client.SendAsync(byteSegments, SocketFlags.None);
}
private IHttpResponse HandleRequest(IHttpRequest httpRequest)
{
if(!this.table.Contains(httpRequest.RequestMethod,
httpRequest.Path))
{
return new TextResult($"Route with method {httpRequest.RequestMethod} and path \"{httpRequest.Path}\"not found.",
HttpResponseStatusCode.NotFound);
}
return this.table.Get(httpRequest.RequestMethod,
httpRequest.Path).Invoke(httpRequest);
}
private async Task<HttpRequest> ReadRequest()
{
var result = new StringBuilder();
var data = new ArraySegment<byte>(new byte[1024]);
while (true)
{
int numberOfBytes = await this.client.ReceiveAsync(data.Array, SocketFlags.None);
if (numberOfBytes == 0) break;
var bytesAsString = Encoding.UTF8.GetString(data.Array, 0,
numberOfBytes);
result.Append(bytesAsString);
if (numberOfBytes < 1023) break;
}
if (result.Length == 0)
{
return null;
}
return new HttpRequest(result.ToString());
}
}
}
When I check the parameters manually and variables in minihttpc.Requests.HttpRequest.ParseHeaders(), everything seems fine. I can't get where the problem is.
string[] header = line.Split(' ').ToArray();
Headers.AddHeader(new HttpHeader(header[0], header[1]));
I can pretty much guarantee you're running into a line that doesn't have a space in it. Maybe there's a line that's empty, for example. That wouldn't be obvious from the Console.WriteLine() that you're doing, because empty lines are kind of invisible.
Good day,
I try that when I connect two documents, the numbered lists are reset. As in the example below.
I use the Xceed.Words.NET DocX libary.
In this Sample, the Template is :
Test Header
List:
1) <-This should be one
And the Result is:
Test Header
List:
1) <-This should be one
Test Header
List:
2) <-This should be one
Test Header
List:
3) <-This should be one
With the following code I am able to create the lists with similar formatting, but the formatting does not match 100%. Does anyone have any idea which way to try otherwise?
Note the number of existing paragraphs and call the function to reset the list after inserting the document.
/// <summary>
/// Insert complete WordFile
/// </summary>
/// <param name="wordFile"></param>
public void InsertWordTemplate(IWordFile wordFile, bool InsertPageBreak)
{
if (wordFile != null && wordFile.IsFileOk)
{
int pargraphCount = Document.Paragraphs.Count - 1;
// NotNeeded for this Problem wordFile.RemoveStyles();
// NotNeeded for this Problem RemoveHeaderAndFooter(wordFile);
Document.InsertDocument(wordFile.Document);
// NotNeeded for this Problem ReplaceSectionBreak(InsertPageBreak, pargraphCount);
ResetNumberedList(pargraphCount);
logger.Info("Word file inserted: " + wordFile.File.FullName);
}
else
{
logger.Warn("Word file is not okay - will not be inserted: " + wordFile?.File?.FullName);
}
}
In the Word document, three different names are used in a list, only from the 4th level is worked with a level. For other Word templates they are called different.
private void ResetNumberedList(int pargraphCount)
{
string styleName1 = "ListNumbers";
string styleName2 = "PIgeordneteListe2Ebene";
string styleName3 = "PIgeordneteListe3Ebene";
NumberedListReset numberedListReset = new NumberedListReset(Document, styleName1, styleName2, styleName3);
bool OnlyFirstFoundList = true;
numberedListReset.Reset(pargraphCount, OnlyFirstFoundList);
}
Below is the helper class with which I try to reset the numbering. I do this by myself
I notice the formatting of the individual list items, create new lists, fill them with the old values, set the styles correctly again and then insert everything into old place.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Xceed.Document.NET;
using Xceed.Words.NET;
namespace PIB.Report.DataWriter.WordExport
{
public class NumberedListReset
{
private readonly DocX _Document;
private readonly string _StyleName1;
private readonly string _StyleName2;
private readonly string _StyleName3;
public NumberedListReset(DocX Document, string StyleName1, string StyleName2, string StyleName3)
{
_Document = Document;
_StyleName1 = StyleName1;
_StyleName2 = StyleName2;
_StyleName3 = StyleName3;
}
public void Reset(int StartParagraphNumber, bool OnlyFirstFinding)
{
for (int i = StartParagraphNumber; i < _Document.Paragraphs.Count; i++)
{
var paragraph = _Document.Paragraphs[i];
if (paragraph.IsListItem == true && paragraph.ListItemType == ListItemType.Numbered && paragraph.StyleName == _StyleName1)
{
//int? numId = GetNumId(paragraph);
//if (numId != -1)
//{
//}
ResetFoundList(ref i);
if (OnlyFirstFinding == true)
{
break;
}
}
}
}
private void ResetFoundList(ref int ParagraphCounter)
{
List<ParagraphMemorize> ParagraphMemorizes = CreateMemorizeListItems(ParagraphCounter);
if (ParagraphMemorizes.Count != 0)
{
RemoveOldParagraphsFromDocument(ParagraphMemorizes);
List numberedList = CreateNewDocumentList();
FillDocumentList(ParagraphMemorizes, numberedList);
List<Paragraph> actualListData = numberedList.Items;
ResetSyleNames(ParagraphMemorizes, actualListData);
InsertNewParagraphsToDocument(ParagraphCounter, actualListData);
ParagraphCounter += ParagraphMemorizes.Count;
}
}
private List<ParagraphMemorize> CreateMemorizeListItems(int ParagraphCounter)
{
List<ParagraphMemorize> ParagraphMemorizes = new List<ParagraphMemorize>();
for (int ii = ParagraphCounter; ii < _Document.Paragraphs.Count; ii++)
{
var paragraph = _Document.Paragraphs[ii];
if (!NameIsKnown(paragraph.StyleName))
{
break;
}
ParagraphMemorize paragraphMemorize = new ParagraphMemorize(paragraph);
paragraphMemorize.ListLevel = GetListLevel(paragraph);
ParagraphMemorizes.Add(paragraphMemorize);
}
return ParagraphMemorizes;
}
private void RemoveOldParagraphsFromDocument(List<ParagraphMemorize> ParagraphMemorizes)
{
ParagraphMemorizes.ForEach(m => _Document.RemoveParagraph(m.Paragraph));
}
private List CreateNewDocumentList()
{
return _Document.AddList(startNumber: 1);
}
private void FillDocumentList(List<ParagraphMemorize> ParagraphMemorizes, List numberedList)
{
for (var ii = 0; ii < ParagraphMemorizes.Count; ii++)
{
//numberedList.AddItem(ParagraphMemorizes[ii].Paragraph); //Raised an Error
ParagraphMemorize paragraphMemorize = ParagraphMemorizes[ii];
int listLevel = GetListLevel(paragraphMemorize);
_Document.AddListItem(numberedList, paragraphMemorize.Text, listLevel);
}
}
private static void ResetSyleNames(List<ParagraphMemorize> ParagraphMemorizes, List<Paragraph> actualListData)
{
for (int ii = 0; ii < actualListData.Count; ii++)
{
actualListData[ii].StyleName = ParagraphMemorizes[ii].StyleName;
}
}
private void InsertNewParagraphsToDocument(int i, List<Paragraph> actualListData)
{
Paragraph paragraph = _Document.Paragraphs[i];
for (int ii = 0; ii < actualListData.Count; ii++)
{
paragraph.InsertParagraphBeforeSelf(actualListData[ii]);
}
}
private bool NameIsKnown(string Name)
{
return Name == _StyleName1 | Name == _StyleName2 | Name == _StyleName3;
}
private int GetListLevel(ParagraphMemorize paragraphMemorize)
{
if (paragraphMemorize.StyleName == _StyleName1)
{
return 0;
}
else if (paragraphMemorize.StyleName == _StyleName2)
{
return 1;
}
else if (paragraphMemorize.StyleName == _StyleName3)
{
return (int)paragraphMemorize.ListLevel;
}
else
{
return 0;
}
}
private int? GetNumId(Paragraph paragraph)
{
var numIds = paragraph.ParagraphNumberProperties.Descendants().Where(e => e.Name.LocalName.Equals("numId"));
foreach (var numId in numIds)
{
XNamespace nsW = Namespace.WordNamespace;
var values = numId.Attributes(XName.Get("val", nsW.ToString()));
foreach (var value in values)
{
int resultId = 0;
int.TryParse(value.Value, out resultId);
return resultId;
}
}
return null;
}
private int? GetListLevel(Paragraph paragraph)
{
var numIds = paragraph.ParagraphNumberProperties.Descendants().Where(e => e.Name.LocalName.Equals("ilvl"));
foreach (var numId in numIds)
{
XNamespace nsW = Namespace.WordNamespace;
var values = numId.Attributes(XName.Get("val", nsW.ToString()));
foreach (var value in values)
{
int resultId = 0;
int.TryParse(value.Value, out resultId);
return resultId;
}
}
return null;
}
private class ParagraphMemorize
{
public Paragraph Paragraph { get; set; }
public string Text { get; set; }
public string StyleName { get; set; }
public int? ListLevel { get; set; }
public ParagraphMemorize(Paragraph Paragraph)
{
this.Paragraph = Paragraph;
this.Text = Paragraph.Text;
this.StyleName = Paragraph.StyleName;
}
}
}
}
I'm trying to extend C# List to use a Print function. Using Console.WriteLine(a.Print()) only shows partial output but a.Print2() work correctly where in a.Print I'm calling a method with return type string and in a.Print2 I'm calling a function with return value void.
using System;
using ExtensionMethods;
using System.Collections.Generic;
namespace ExtensionMethods
{
public static class ExtensionClass
{
public static int PlusFive(this int input)
{
return input + 5;
}
static public string Print(this List<int> input)
{
int i;
string output = "";
for (i = 0; i < input.Count - 1; i++)
{
output = input[i].ToString() + ", ";
}
output += input[i].ToString();
return output;
// Outputs 2, 3
}
static public void Print2(this List<int> input)
{
int i;
for (i = 0; i < input.Count - 1; i++)
{
Console.Write(input[i].ToString() + ", ");
}
Console.Write(input[i].ToString());
// Outputs 1, 2 ,3
}
}
}
namespace LearningCSharp
{
class Program
{
static void Main(string[] args)
{
List<int> a = new List<int>(){1, 2, 3};
// int b = 2;
Console.WriteLine(a.Print());
a.Print2();
}
}
}
Because your Print() method is broken. In the loop you always set output to a new string. You're missing the plus:
static public string Print(this List<int> input)
{
int i;
string output = "";
for (i = 0; i < input.Count - 1; i++)
{
// missing plus here
output += input[i].ToString() + ", ";
}
return output;
}
Note however that there are better possibilites to concat strings. One solution here could be:
static public string Print(this List<int> input)
{
return string.Join(", ", input);
}
I have two files F1.txt and F2.txt. F1.txt contains some contents like
U1,U2
U1,U5
U3,U4
U2,U1
U3,U4
Essentially U1,U2 and U2,U1 mean the same . So now I want to write the distinct contents to a file F2.txt i.e. after writing F2.txt should contain
U1,U2
U1,U5
U3,U4
I tried the below but that did not work out.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StringInFileTechchef
{
class Program
{
static void Main(string[] args)
{
string line = "";
using (StreamReader sr = new StreamReader(#"C:\Users\Chiranjib\Desktop\F1.txt"))
{
while((line=sr.ReadLine()) !=null)
{
if (!File.ReadAllText(#"C:\Users\Chiranjib\Desktop\F2.txt").Contains(line))
{
//char[] array = line.ToCharArray();
//Array.Reverse(array);
//string temp = new string(array);
string temp1 = line.Substring(0, 2);
string temp2 = line.Substring(3, 2);
if (!File.ReadAllText(#"C:\Users\Chiranjib\Desktop\F2.txt").Contains(temp2 + "," + temp1))
{
using (StreamWriter sw = new StreamWriter(#"C:\Users\Chiranjib\Desktop\F2.txt"))
{
sw.WriteLine(line);
Console.WriteLine(line);
}
}
}
}
}
Console.ReadKey();
}
}
}
What am I missing ? How to achieve the scenario.
Here is how I would do it:
Take each line and split it to a string[]
Sort the string[]
Join the string[] back to a string
Take the distinct strings
var distinct = File.ReadLines("TextFile2.txt")
.Select(l => String.Join(",", l.Split(',').OrderBy(i => i)))
.Distinct();
File.WriteAllLines("F2.txt", distinct);
Another method:
HashSet<string> uniqueLines = new HashSet<string>();
foreach(string line in File.ReadLines("F1.txt"))
{
if (uniqueLines.Contains(line))
continue;
string[] tokens = line.Split(',');
string reversedLine = string.Join(",", tokens.Reverse());
if (uniqueLines.Contains(reversedLine))
continue;
uniqueLines.Add(line);
}
File.WriteAllLines("F2.txt", uniqueLines);
This worked for me. Basically assuming that there are two strings separated by comma always, I just filter them out using a HashSet. May be an overkill but works for small files.
#region
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
#endregion
namespace StringInFileTechchef
{
internal class Program
{
private static void Main(string[] args)
{
HashSet<WordCombo> existingWordCombos = GetWordCombos(File.ReadAllLines(#"C:\Users\Chiranjib\Desktop\F2.txt"));
HashSet<WordCombo> newWordCombos = GetWordCombos(File.ReadAllLines(#"C:\Users\Ganesh\Chiranjib\F1.txt"));
foreach (WordCombo newWordCombo in newWordCombos)
{
existingWordCombos.Add(newWordCombo);
}
StringBuilder stringBuilder = new StringBuilder();
foreach (WordCombo existingWordCombo in existingWordCombos)
{
stringBuilder.AppendFormat("{0},{1}{2}", existingWordCombo.SmallerWord, existingWordCombo.BiggerWord, Environment.NewLine);
}
File.WriteAllText(#"C:\Users\Ganesh\Desktop\F2.txt", stringBuilder.ToString());
}
private static HashSet<WordCombo> GetWordCombos(IEnumerable<string> lines)
{
HashSet<WordCombo> wordCombos = new HashSet<WordCombo>();
foreach (string line in lines)
{
string[] splitWords = line.Split(new[] {','});
wordCombos.Add(new WordCombo(splitWords[0], splitWords[1]));
}
return wordCombos;
}
private class WordCombo
{
public string BiggerWord { get; private set; }
public string SmallerWord { get; private set; }
public WordCombo(string part1, string part2)
{
if (0 < string.Compare(part1, part2, StringComparison.InvariantCultureIgnoreCase))
{
BiggerWord = part1;
SmallerWord = part2;
}
else
{
BiggerWord = part2;
SmallerWord = part1;
}
}
protected bool Equals(WordCombo other)
{
return string.Equals(BiggerWord, other.BiggerWord, StringComparison.InvariantCultureIgnoreCase)
&& string.Equals(SmallerWord, other.SmallerWord, StringComparison.InvariantCultureIgnoreCase);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((WordCombo) obj);
}
public override int GetHashCode()
{
unchecked
{
return ((BiggerWord != null ? BiggerWord.ToLowerInvariant().GetHashCode() : 0)*397) ^
(SmallerWord != null ? SmallerWord.ToLowerInvariant().GetHashCode() : 0);
}
}
}
}
}
My program reads from a text file delimited with a comma. The answers are an array of strings which I can't get to populate at the console.
The Question will show up, the correct Answer(a single char) will show up and the explanation will show up, it is just the array with the answers I am having problems with.
I will supply the code below.
The Question Unit( Structure of the Questions from the text file)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HoodTalkTrivia
{
class QuestionUnit
{
private string correctAnswer;
private string explanation;
private string question;
private string[] answer = new string[4];
public string CorrectAnswer
{
get { return correctAnswer; }
set { correctAnswer = value; }
}
public string Explanation
{
get { return explanation; }
set { explanation = value; }
}
public string Question
{
get { return question; }
set { question = value; }
}
public string[] Answer
{
get {return answer; }
set { answer = value; }
}
}
}
The Question Bank
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace HoodTalkTrivia
{
class QuestionBank
{
List<QuestionUnit> theQuestionsList = new List<QuestionUnit>();
// private string[] Questions;
const int NUM_ANSWERS = 4;
const int NUM_QUESTIONS = 5;
public int GetNumberOfAnswers
{
get { return NUM_ANSWERS; }
}
public int GetNumberOfQuestions
{
get { return NUM_QUESTIONS; }
}
public string GetCorrectAnswer(int index)
{
return theQuestionsList[index].CorrectAnswer;
}
public string GetExplanation(int index)
{
return theQuestionsList[index].Explanation;
}
public string GetQuestion(int index)
{
return theQuestionsList[index].Question;
}
public string[] GetAnswer(int index)
{
return theQuestionsList[index].Answer;
}
public bool ReadQuestionFile()
{
bool success = true;
FileInfo httSourceFile = new FileInfo("Questions.txt");
string line;
string[] fields;
char[] delimiter = { System.Convert.ToChar(",") };
QuestionUnit httQuestionUnit;
//int i = 0;
try
{
StreamReader httReader = httSourceFile.OpenText();
line = httReader.ReadLine();
while (line != null)
{
httQuestionUnit = new QuestionUnit();
fields = line.Split(delimiter);
httQuestionUnit.Question = fields[0];
string[] aArray = new string[4];
aArray[0] = fields[1];
aArray[1] = fields[2];
aArray[2] = fields[3];
aArray[3] = fields[4];
httQuestionUnit.Answer = aArray;
httQuestionUnit.CorrectAnswer = fields[5];
httQuestionUnit.Explanation = fields[6];
theQuestionsList.Add(httQuestionUnit);
line = httReader.ReadLine();
}
}
catch
{
success = false;
}
return success;
}
}
}
And the main
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HoodTalkTrivia
{
class HoodTalkTriviaGame
{
HoodTalkTriviaStrings myGameStrings;
public void PlayAgain()
{
}
public void Play()
{
QuestionBank myQuestions = new QuestionBank();
DisplayWelcome();
myQuestions.ReadQuestionFile();
for (int i = 0; i < myQuestions.GetNumberOfQuestions; i++)
{
Console.WriteLine(myQuestions.GetQuestion(i));
for (int j = 0; j < myQuestions.GetNumberOfAnswers; j++)
{
Console.WriteLine(myQuestions.GetAnswer(j));
}
// Console.WriteLine(myQuestions.GetCorrectAnswer(i));
Console.WriteLine("Make a selection, A - D");
Console.ReadLine();
}
}
public void DisplayWelcome()
{
myGameStrings = new HoodTalkTriviaStrings();
myGameStrings.WelcomeString();
}
public char PromptForGuess()
{
char guess = ' ';
return guess;
}
}
}
Here is an image of what i am getting at the console.
GetAnswer method returning an array of strings, so you are seeing the name of the type of your array in the console instead of the contents.
You can change your code like this:
Change this code:
for (int j = 0; j < myQuestions.GetNumberOfAnswers; j++)
{
Console.WriteLine(myQuestions.GetAnswer(j));
}
To:
var answers = myQuestions.GetAnswer(i);
for (int j = 0; j < answers.Length; j++)
{
Console.WriteLine(answers[j]);
}
Then you should see the answers of your question in the console.
You need to use the second index for the possible answers, because Answer is an array again:
for (int j = 0; j < myQuestions.GetNumberOfAnswers; j++)
{
Console.WriteLine(myQuestions.GetAnswer(i)[j]);
}
An alternative way of solving the problem is to change the acessor method:
public string GetAnswer(int questionIndex, int answerIndex)
{
return theQuestionsList[questionIndex].Answer[answerIndex];
}
And then the loop will be:
for (int j = 0; j < myQuestions.GetNumberOfAnswers; j++)
{
Console.WriteLine(myQuestions.GetAnswer(i, j));
}
Now the signature of the GetAnswer makes it impossible to forget the second index. It would also be helpful to rename the Answer property to Answers. This would remind you that an array is returned.
I think your solution a bit over-designed. An overall simplified approach would make it easier to use the classes. If the QuestionBank simply had a property returning an enumeration of question units this would be enough. No need for all the GetXYZ methods.
class QuestionBank
{
List<QuestionUnit> theQuestionsList = new List<QuestionUnit>();
public IEnumerable<QuestionUnit> Questions { get { return theQuestionsList; } }
...
}
Returning an IEnumerable<QuestionUnit> has the advantage over returning a List<QuestionUnit> that the real type of the question list is not made public, thus allowing you to change the implementation at any time without invalidating any code that accesses the questions from the outside.
Then the loops will become easier:
foreach (QuestionUnit questionUnit in myQuestions)
{
Console.WriteLine(questionUnit.Question);
foreach (string answer in questionUnit.Answers)
{
Console.WriteLine(answer);
}
Console.WriteLine("Make a selection, A - D");
Console.ReadLine();
}