mirror of
https://github.com/alexmickelson/canvasManagement.git
synced 2026-03-25 23:28:33 -06:00
can parse at least some markdown quiz questions
This commit is contained in:
@@ -161,6 +161,7 @@ AllowedAttempts: -1
|
|||||||
Description: this is the
|
Description: this is the
|
||||||
multi line
|
multi line
|
||||||
description
|
description
|
||||||
|
---
|
||||||
";
|
";
|
||||||
var quiz = LocalQuiz.ParseMarkdown(rawMarkdownQuiz);
|
var quiz = LocalQuiz.ParseMarkdown(rawMarkdownQuiz);
|
||||||
|
|
||||||
@@ -173,4 +174,47 @@ description
|
|||||||
multi line
|
multi line
|
||||||
description");
|
description");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCanParseQuizWithQuestions()
|
||||||
|
{
|
||||||
|
var rawMarkdownQuiz = @"
|
||||||
|
Name: Test Quiz
|
||||||
|
LockAtDueDate: true
|
||||||
|
ShuffleAnswers: true
|
||||||
|
OneQuestionAtATime: false
|
||||||
|
DueAt: 2023-08-21T23:59:00
|
||||||
|
LockAt: 2023-08-21T23:59:00
|
||||||
|
AssignmentGroup: Assignments
|
||||||
|
AllowedAttempts: -1
|
||||||
|
Description: this is the
|
||||||
|
multi line
|
||||||
|
description
|
||||||
|
---
|
||||||
|
Points: 2
|
||||||
|
`some type` of question
|
||||||
|
|
||||||
|
with many
|
||||||
|
|
||||||
|
```
|
||||||
|
lines
|
||||||
|
```
|
||||||
|
|
||||||
|
*a) true
|
||||||
|
b) false
|
||||||
|
|
||||||
|
endline
|
||||||
|
---
|
||||||
|
";
|
||||||
|
|
||||||
|
var quiz = LocalQuiz.ParseMarkdown(rawMarkdownQuiz);
|
||||||
|
var firstQuestion = quiz.Questions.First();
|
||||||
|
firstQuestion.Points.Should().Be(2);
|
||||||
|
firstQuestion.Text.Should().Contain("```");
|
||||||
|
firstQuestion.Text.Should().Contain("`some type` of question");
|
||||||
|
firstQuestion.Answers.First().Text.Should().Be("true");
|
||||||
|
firstQuestion.Answers.First().Correct.Should().BeTrue();
|
||||||
|
firstQuestion.Answers.ElementAt(1).Correct.Should().BeFalse();
|
||||||
|
firstQuestion.Answers.ElementAt(1).Text.Should().Contain("endline");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -61,9 +61,22 @@ Description: {Description}
|
|||||||
public static LocalQuiz ParseMarkdown(string input)
|
public static LocalQuiz ParseMarkdown(string input)
|
||||||
{
|
{
|
||||||
|
|
||||||
var splitInput = input.Split(Environment.NewLine + Environment.NewLine);
|
var splitInput = input.Split("---" + Environment.NewLine);
|
||||||
var settings = splitInput[0];
|
var settings = splitInput[0];
|
||||||
|
var quizWithoutQuestions = getQuizWithOnlySettings(settings);
|
||||||
|
|
||||||
|
var questions = splitInput[1..]
|
||||||
|
.Where(str => !string.IsNullOrWhiteSpace(str))
|
||||||
|
.Select(q => LocalQuizQuestion.ParseMarkdown(q))
|
||||||
|
.ToArray();
|
||||||
|
return quizWithoutQuestions with
|
||||||
|
{
|
||||||
|
Questions = questions
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LocalQuiz getQuizWithOnlySettings(string settings)
|
||||||
|
{
|
||||||
var name = extractLabelValue(settings, "Name");
|
var name = extractLabelValue(settings, "Name");
|
||||||
var lockAtDueDate = bool.Parse(extractLabelValue(settings, "LockAtDueDate"));
|
var lockAtDueDate = bool.Parse(extractLabelValue(settings, "LockAtDueDate"));
|
||||||
var shuffleAnswers = bool.Parse(extractLabelValue(settings, "ShuffleAnswers"));
|
var shuffleAnswers = bool.Parse(extractLabelValue(settings, "ShuffleAnswers"));
|
||||||
@@ -89,6 +102,7 @@ Description: {Description}
|
|||||||
Questions = new LocalQuizQuestion[] { }
|
Questions = new LocalQuizQuestion[] { }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static string extractLabelValue(string input, string label)
|
static string extractLabelValue(string input, string label)
|
||||||
{
|
{
|
||||||
string pattern = $@"{label}: (.*?)\n";
|
string pattern = $@"{label}: (.*?)\n";
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace LocalModels;
|
namespace LocalModels;
|
||||||
|
|
||||||
public record LocalQuizQuestion
|
public record LocalQuizQuestion
|
||||||
@@ -21,7 +23,7 @@ public record LocalQuizQuestion
|
|||||||
|
|
||||||
|
|
||||||
var questionTypeIndicator = isMultipleChoice
|
var questionTypeIndicator = isMultipleChoice
|
||||||
? $"{correctIndicator}{questionLetter}) "
|
? $"{correctIndicator}{questionLetter}) "
|
||||||
: $"[{correctIndicator}] ";
|
: $"[{correctIndicator}] ";
|
||||||
|
|
||||||
var textWithSpecificNewline = answer.Text.Replace(Environment.NewLine, Environment.NewLine + " ");
|
var textWithSpecificNewline = answer.Text.Replace(Environment.NewLine, Environment.NewLine + " ");
|
||||||
@@ -35,6 +37,67 @@ public record LocalQuizQuestion
|
|||||||
---
|
---
|
||||||
";
|
";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly string[] validFirstAnswerDelimiters = new string[] { "*a)", "a)", "[ ]", "[*]" };
|
||||||
|
public static LocalQuizQuestion ParseMarkdown(string input)
|
||||||
|
{
|
||||||
|
var lines = input.Split(Environment.NewLine);
|
||||||
|
var firstLineIsPoints = lines.First().Contains("points: ", StringComparison.CurrentCultureIgnoreCase);
|
||||||
|
int points = firstLineIsPoints ? int.Parse(lines.First().Split(": ")[1]) : 1;
|
||||||
|
|
||||||
|
var linesWithoutPoints = firstLineIsPoints ? lines[1..] : lines;
|
||||||
|
|
||||||
|
var linesWithoutAnswers = linesWithoutPoints
|
||||||
|
.TakeWhile(line => !validFirstAnswerDelimiters.Any(prefix => line.TrimStart().StartsWith(prefix)))
|
||||||
|
.ToArray();
|
||||||
|
var description = string.Join(Environment.NewLine, linesWithoutAnswers);
|
||||||
|
|
||||||
|
|
||||||
|
LocalQuizQuestionAnswer[] answers = getAnswers(linesWithoutPoints);
|
||||||
|
|
||||||
|
return new LocalQuizQuestion()
|
||||||
|
{
|
||||||
|
Text = description,
|
||||||
|
Points = points,
|
||||||
|
Answers = answers
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LocalQuizQuestionAnswer[] getAnswers(string[] linesWithoutPoints)
|
||||||
|
{
|
||||||
|
var indexOfAnswerStart = linesWithoutPoints
|
||||||
|
.ToList()
|
||||||
|
.FindIndex(
|
||||||
|
l => validFirstAnswerDelimiters.Any(prefix => l.TrimStart().StartsWith(prefix))
|
||||||
|
);
|
||||||
|
var answerLinesRaw = linesWithoutPoints[indexOfAnswerStart..];
|
||||||
|
|
||||||
|
var answerStartPattern = @"^(\*?[a-z]\))|\[\s*\]|\[\*\]";
|
||||||
|
var answerLines = answerLinesRaw.Aggregate(new List<string>(), (acc, line) =>
|
||||||
|
{
|
||||||
|
if (!Regex.IsMatch(line, answerStartPattern))
|
||||||
|
{
|
||||||
|
if (acc.Count != 0) // Append to the previous line if there is one
|
||||||
|
{
|
||||||
|
int lastIndex = acc.Count - 1;
|
||||||
|
acc[lastIndex] += Environment.NewLine + line;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
acc.Add(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
acc.Add(line); // Add as a new line if it matches the pattern
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
});
|
||||||
|
|
||||||
|
var answers = answerLines.Select(LocalQuizQuestionAnswer.ParseMarkdown).ToArray();
|
||||||
|
return answers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class QuestionType
|
public static class QuestionType
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace LocalModels;
|
namespace LocalModels;
|
||||||
|
|
||||||
public record LocalQuizQuestionAnswer
|
public record LocalQuizQuestionAnswer
|
||||||
@@ -11,4 +13,17 @@ public record LocalQuizQuestionAnswer
|
|||||||
|
|
||||||
public string HtmlText => Markdig.Markdown.ToHtml(Text);
|
public string HtmlText => Markdig.Markdown.ToHtml(Text);
|
||||||
|
|
||||||
|
public static LocalQuizQuestionAnswer ParseMarkdown(string input)
|
||||||
|
{
|
||||||
|
var isCorrect = input[0] == '*' || input[1] == '*';
|
||||||
|
string startingQuestionPattern = @"^(?:\*[a-z]\))|\[\s*\]|\[\*\] ";
|
||||||
|
var text = Regex.Replace(input, startingQuestionPattern, string.Empty).Trim();
|
||||||
|
|
||||||
|
return new LocalQuizQuestionAnswer()
|
||||||
|
{
|
||||||
|
Correct = isCorrect,
|
||||||
|
Text=text,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user