1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/lunarsf-Lunar-Markdown-Editor

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Это зеркальный репозиторий, синхронизируется ежедневно с исходного репозитория.
Клонировать/Скачать
QuestionValidateManager.cs 30 КБ
Копировать Редактировать Исходные данные Просмотреть построчно История
LunarSF Отправлено 9 лет назад ab5a981
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LunarSF.SHomeWorkshop.LunarMarkdownEditor
{
/// <summary>
/// 与填空题相关的方法。
/// </summary>
internal static class QuestionValidateManager
{
/// <summary>
/// [静态构造方法]初始化空白字符数组,以用来进行文本操作。
/// </summary>
static QuestionValidateManager()
{
blankChars = new char[6];
blankChars[0] = ' ';
blankChars[1] = '\t';
blankChars[2] = ' ';//全角空格
blankChars[3] = '\r';//验证时不需要
blankChars[4] = '\n';
}
private static char[] blankChars;
/// <summary>
/// 空白字符数组,用以进行文本操作。
/// </summary>
public static char[] BlankChars
{
get { return blankChars; }
}
/// <summary>
/// 按照“全部为选择题”的规则来验证整个文档的合法性。
/// </summary>
/// <param name="documentText">要验证的文档的全部文本。</param>
/// <param name="errorMsg">返回的错误消息。</param>
/// <returns>验证合法会返回真。</returns>
public static bool ValidateAsTestPaper(string documentText, StringBuilder errorMsg = null)
{
//忽略所有空白字符,不能用Trim,因为Trim只去首尾。
documentText = documentText.Replace("\r\n", "").Replace("\t", "").Replace(" ", "").Replace(" ", "");
//去除文件信息那几行
if (documentText.StartsWith("<<<信息>"))
{
int indexOfEndTitleTag = documentText.IndexOf("<信息>>>");
if (indexOfEndTitleTag < 0)
{
if (errorMsg != null)
{
errorMsg.Append("文档非法,文件信息部分缺少结束标记“<信息>>>”。请使用自动完成功能在行首添加“信息”并编辑文件信息文本。");
}
}
else
{
documentText = documentText.Substring(indexOfEndTitleTag + 6);
}
}
string[] separator = new string[2];
separator[0] = "试题>>";
separator[1] = "〓〓〓〓〓〓";
string[] answerSeparator = new string[1];
answerSeparator[0] = "答案>>";
string[] errorSeparator = new string[1];
errorSeparator[0] = "错项>>";
string[] questionTexts = documentText.Split(separator, StringSplitOptions.RemoveEmptyEntries);
if (questionTexts.Length <= 0)
{
if (errorMsg != null)
{
errorMsg.Append("没有找到任何试题,此文档对于试题演示操作无意义。");
}
}
for (int i = 1; i <= questionTexts.Length; i++)
{
string questionText = questionTexts[i - 1];
//先找出试题文本
if (questionText.Contains("<<<信息>") || questionText.Contains("<信息>>>"))
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法,试题文本中不能包含“信息”标签。\r\n", i));
}
}
if (questionText.Contains("标题>>"))
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法,试题文本中不能包含“标题”标签。\r\n", i));
}
}
if (questionText.Contains("日期>>"))
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法,试题文本中不能包含“日期”标签。\r\n", i));
}
}
if (questionText.Contains("作者>>"))
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法,试题文本中不能包含“作者”标签。\r\n", i));
}
}
if (questionText.Contains("缉录>>"))
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法,试题文本中不能包含“缉录”标签。\r\n", i));
}
}
if (questionText.Contains("辑录>>"))
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法,试题文本中不能包含“辑录”标签。\r\n", i));
}
}
if (questionText.Contains("电邮>>"))
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法,试题文本中不能包含“电邮”标签。\r\n", i));
}
}
if (questionText.Contains("备注>>"))
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法,试题文本中不能包含“备注”标签。\r\n", i));
}
}
if (questionText.StartsWith("答案>>") || questionText.StartsWith("错项>>") || questionText.StartsWith("解析>>"))
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法,没有试题文本。试题不能以“答案”、“错项”或“解析”开头。\r\n", i));
}
}
else
{
string[] questionTitleAndAnswers = questionText.Split(answerSeparator, StringSplitOptions.None);//这里不去除空数组,反正不是按换行符来分的。
if (questionTitleAndAnswers.Length <= 0)
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法,没有试题文本,没有答案,也未提供错项。\r\n", i));
}
}
else if (questionTitleAndAnswers.Length == 1)
{
//为什么要去除呢?因为填空题就是没有答案与错项的——【填充文本】就是答案。
//if (errorMsg != null)
//{
// errorMsg.Append(string.Format("第{0}题非法,只有试题文本,没有答案,也未提供错项。\r\n", i));
//}
int fillBlankCount = -1;
string questionTitleText = questionTitleAndAnswers[0];
StringBuilder questionErrorMsg = new StringBuilder();
if (ValidatePairOfBrackets(questionTitleText, ref fillBlankCount, true, questionErrorMsg))
{
if (fillBlankCount <= 0)
{
if (errorMsg != null) errorMsg.Append(string.Format("第{0}题非法,试题文本未中没有设置填空项。\r\n", i));
}
}
else
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法," + questionErrorMsg.ToString(), i));
}
}
}
else
{
//判断答案数目是否符合
//先判断题目是否合法,规则如下:
//①至少一个括弧对(包含着填充项)。
//②括弧要匹配
//③有一个填充项就要有一个“答案区域”
//④“答案区域”中可以包含解析,但“解析>>”字样不能出现在开头。
string questionTitleText = questionTitleAndAnswers[0];
int fillBlankCount = -1;
StringBuilder questionErrorMsg = new StringBuilder();
if (ValidatePairOfBrackets(questionTitleText, ref fillBlankCount, true, questionErrorMsg))
{
if (fillBlankCount != questionTitleAndAnswers.Length - 1)
{
if (errorMsg != null) errorMsg.Append(string.Format("第{0}题非法,提供的答案数目与试题中的填空项数目不一致。\r\n", i));
}
else
{
for (int i2 = 1; i2 < questionTitleAndAnswers.Length; i2++)
{
string answerText = questionTitleAndAnswers[i2];
if (answerText.StartsWith("解析>>"))
{
if (errorMsg != null) errorMsg.Append(string.Format("第 {0} 题,第 {1} 个填充项未提供答案,或答案解析位置不正确。", i, i2));
}
string[] errorItems = answerText.Split(errorSeparator, StringSplitOptions.RemoveEmptyEntries);
if (errorItems.Length < 2)//第一项是答案,要求至少一个答案、一个备选的错项。
{
if (errorMsg != null) errorMsg.Append(string.Format("第 {0} 题,第 {1} 个填充项未提供答案或未提供备选的错项。\r\n", i, i2));
}
else
{
for (int i3 = 1; i3 < errorItems.Length; i3++)
{
if (errorItems[i3].StartsWith("解析>>") || errorItems[i3].Length <= "错项>>".Length)
{
if (errorMsg != null) errorMsg.Append(string.Format("第 {0} 题,第 {1} 个填充项的某个错项未提供文本,或错项解析位置不正确。\r\n", i, i2));
}
}
}
}
}
}
else
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法," + questionErrorMsg.ToString(), i));
}
}
}
}
}
if (string.IsNullOrEmpty(errorMsg.ToString())) return true;
return false;
}
/// <summary>
/// 用于校验“试题>>”文本是否合法。★注意,此时,选择题题干文本不支持多行!!!
/// </summary>
/// <param name="sourceText">要校验的文本。</param>
/// <param name="allowJoinFillBlanks">是否允许两对括弧连续出现。</param>
/// <param name="errorMsg">错误消息。</param>
/// <returns>如果合法,返回真。否则返回假。</returns>
public static bool ValidatePairOfBrackets(string sourceText, ref int fillblankCount, bool allowJoinFillBlanks = true, StringBuilder errorMsg = null, bool allowNoFillBlank = false)
{
if (string.IsNullOrEmpty(sourceText))
{
if (errorMsg != null)
{
errorMsg.Append("没有文本。");
}
return false;
}
if (allowNoFillBlank == false)
{
if (sourceText.Contains("【") == false || sourceText.Contains("】") == false)
{
if (errorMsg != null)
{
errorMsg.Append("没有答案文本(答案文本应以方括号对【】包围。)");
}
return false;
}
}
if (sourceText.Contains("试题>>"))
{
sourceText = sourceText.TrimStart(blankChars);
if (sourceText.StartsWith("试题>>"))
{
sourceText = sourceText.Substring(4);
}
}
if (sourceText.Contains("解析>>"))
{
if (errorMsg != null)
errorMsg.Append("“答案”之前不应该有“解析”。\r\n");
return false;
}
List<int> startBracketIndexesList = new List<int>();
List<int> endBracketIndexesList = new List<int>();
for (int i = 0; i < sourceText.Length; i++)
{
char c = sourceText[i];
if (c == '【')
{
startBracketIndexesList.Add(i);
}
else if (c == '】')
{
endBracketIndexesList.Add(i);
}
}
#region 对两个列表比较之前,先保证两个列表成员数目相等。
if (allowJoinFillBlanks == false)
{
if (startBracketIndexesList.Count <= 0 || endBracketIndexesList.Count <= 0)
{
if (errorMsg != null)
errorMsg.Append("试题无填充项。\r\n");
return false;
}
}
if (startBracketIndexesList.Count < endBracketIndexesList.Count)
{
for (int i = 0; i < (endBracketIndexesList.Count - startBracketIndexesList.Count); i++)
{
startBracketIndexesList.Add(-1);
}
if (errorMsg != null)
errorMsg.Append("括弧数目不等。\r\n");
return false;
}
else if (startBracketIndexesList.Count > endBracketIndexesList.Count)
{
for (int i = 0; i < (startBracketIndexesList.Count - endBracketIndexesList.Count); i++)
{
endBracketIndexesList.Add(-1);
}
if (errorMsg != null)
errorMsg.Append("括弧数目不等。\r\n");
}
else
{
fillblankCount = startBracketIndexesList.Count;
}
#endregion
for (int i = 0; i < startBracketIndexesList.Count; i++)
{
if (startBracketIndexesList[i] == -1 || endBracketIndexesList[i] == -1)
{
if (errorMsg != null)
errorMsg.Append("首尾括弧不匹配。\r\n");
return false;
}
if (startBracketIndexesList[i] >= endBracketIndexesList[i])
{
if (errorMsg != null)
errorMsg.Append("首尾括弧不匹配。\r\n");
return false;
}
if (startBracketIndexesList[i] + 1 == endBracketIndexesList[i])
{
//首尾括弧之间没有答案文本
if (errorMsg != null)
errorMsg.Append("首尾括弧之间没有答案文本。\r\n");
return false;
}
}
for (int i = 0; i < startBracketIndexesList.Count - 1; i++)
{
//前一个尾括弧必须在后一个首括弧之前
if (endBracketIndexesList[i] >= startBracketIndexesList[i + 1])
{
if (errorMsg != null)
errorMsg.Append("括弧对交错。\r\n");
return false;
}
if (allowJoinFillBlanks == false)
{
if (endBracketIndexesList[i] + 1 == startBracketIndexesList[i + 1])
{
//前一个尾括弧正好在后一个首括弧前1位——两个填空没必要连在一起——这时候做成一个填空就可以了。
if (errorMsg != null)
errorMsg.Append("两个填充项连在一起,这没必要。\r\n");
return false;
}
}
}
return true;
}
/// <summary>
/// 用于演示前的验证。规则比选择题宽松得多。
/// </summary>
/// <param name="documentText"></param>
/// <param name="errorMsg"></param>
/// <returns></returns>
public static bool ValidateForPresentation(string documentText, StringBuilder errorMsg = null)
{
//忽略所有空白字符,不能用Trim,因为Trim只去首尾。
documentText = documentText.Replace("\r\n", "").Replace("\t", "").Replace(" ", "").Replace(" ", "");
//去除文件信息那几行
if (documentText.StartsWith("<<<信息>"))
{
int indexOfEndTitleTag = documentText.IndexOf("<信息>>>");
if (indexOfEndTitleTag < 0)
{
if (errorMsg != null)
{
errorMsg.Append("文档非法,文件信息部分缺少结束标记“<信息>>>”。请使用自动完成功能在行首添加“信息”并编辑文件信息文本。或者去除这部分。");
}
}
else
{
documentText = documentText.Substring(indexOfEndTitleTag + 6);
}
}
string[] separator = new string[2];
separator[0] = "试题>>";
separator[1] = "〓〓〓〓〓〓";
string[] answerSeparator = new string[1];
answerSeparator[0] = "答案>>";
string[] errorSeparator = new string[1];
errorSeparator[0] = "错项>>";
string[] questionTexts = documentText.Split(separator, StringSplitOptions.RemoveEmptyEntries);
if (questionTexts.Length <= 0)
{
if (errorMsg != null)
{
errorMsg.Append("没有找到任何试题,此文档对于试题演示操作无意义。");
}
}
for (int i = 1; i <= questionTexts.Length; i++)
{
string questionText = questionTexts[i - 1];
//先找出试题文本
if (questionText.Contains("<<<信息>") || questionText.Contains("<信息>>>"))
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法,试题文本中不能包含“信息”标签。\r\n", i));
}
}
if (questionText.Contains("标题>>"))
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法,试题文本中不能包含“标题”标签。\r\n", i));
}
}
if (questionText.Contains("日期>>"))
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法,试题文本中不能包含“日期”标签。\r\n", i));
}
}
if (questionText.Contains("作者>>"))
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法,试题文本中不能包含“作者”标签。\r\n", i));
}
}
if (questionText.Contains("缉录>>"))
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法,试题文本中不能包含“缉录”标签。\r\n", i));
}
}
if (questionText.Contains("辑录>>"))
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法,试题文本中不能包含“辑录”标签。\r\n", i));
}
}
if (questionText.Contains("电邮>>"))
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法,试题文本中不能包含“电邮”标签。\r\n", i));
}
}
if (questionText.Contains("备注>>"))
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法,试题文本中不能包含“备注”标签。\r\n", i));
}
}
if (questionText.StartsWith("答案>>") || questionText.StartsWith("错项>>") || questionText.StartsWith("解析>>"))
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法,没有试题文本。试题不能以“答案”、“错项”或“解析”开头。\r\n", i));
}
}
else
{
string[] questionTitleAndAnswers = questionText.Split(answerSeparator, StringSplitOptions.None);//这里不去除空数组,反正不是按换行符来分的。
if (questionTitleAndAnswers.Length <= 0)
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法,没有试题文本,没有答案,也未提供错项。\r\n", i));
}
}
else if (questionTitleAndAnswers.Length == 1)
{
//没有答案项和错项,是填空题
int fillBlankCount = -1;
string questionTitleText = questionTitleAndAnswers[0];
StringBuilder questionErrorMsg = new StringBuilder();
if (ValidatePairOfBrackets(questionTitleText, ref fillBlankCount, true, questionErrorMsg, true) == false)
{
if (errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法," + questionErrorMsg.ToString(), i));
}
}
}
else//有标题、有答案项
{
//判断答案数目是否符合
//先判断题目是否合法,规则如下:
//①以括弧对包含着填充项。
//②括弧要匹配
//③有一个填充项就要有一个“答案区域”
//④“答案区域”中可以包含解析,但“解析>>”字样不能出现在开头。
string questionTitleAndAnswerText = questionTitleAndAnswers[0];
int fillBlankCount = -1;//标题中填充项(指标题文本中用一对方括号括起来的文本片段)的数目
StringBuilder questionErrorMsg = new StringBuilder();
if (ValidatePairOfBrackets(questionTitleAndAnswerText, ref fillBlankCount, true, questionErrorMsg, false))//不允许没有填充项。
{
//标题中有填充项、标题外提供了答案项(错项附属于答案项,一个答案项可备零到多个错项,但主观题的答案项不应提供错项)。
if (fillBlankCount != questionTitleAndAnswers.Length - 1)
{
if (fillBlankCount != 0)
{
//当填充项与提供的答案数目不一致时,要么没有答案(填空题);要么就是出错了。
//此分支questionTitleAndAnswers.Length > 1
if (errorMsg != null) errorMsg.Append(string.Format("第{0}题非法,提供了答案,但提供的答案数目与试题中的填充项数目不一致。\r\n", i));
}
else
{
//当提供了答案和解析时,如果填空项为0,则说明这是一主观题。
//主观题也可以有多个答案项和解析。但主观题中不应该有“错项”。
bool hasErrorItem = false;
for (int i4 = 1; i4 < questionTitleAndAnswers.Length; i4++)
{
if (questionTitleAndAnswers[i4].Contains("错项>>"))
{
hasErrorItem = true;
break;
}
}
if (hasErrorItem)
{
if (errorMsg != null) errorMsg.Append(string.Format("第{0}题非法,没有填充项的试题应是主观题,但主观题的答案中不应出现“错项>>”字样。\r\n", i));
}
}
}
else//填充项数目正好等于提供的答案的数目。这应该是选择题。
{
for (int i2 = 1; i2 < questionTitleAndAnswers.Length; i2++)
{
string answerText = questionTitleAndAnswers[i2];
if (answerText.StartsWith("解析>>"))
{
if (errorMsg != null) errorMsg.Append(string.Format("第 {0} 题,第 {1} 个填充项未提供答案,或答案解析位置不正确。", i, i2));
}
if (fillBlankCount > 0)//填空有填充项但无答案项、错项;判断没有填充项、没有答案项。
{
string[] errorItems = answerText.Split(errorSeparator, StringSplitOptions.RemoveEmptyEntries);
if (errorItems.Length == 1)//要么是填空、判断(没有答案项);要么是选择(至少一个答案、一个错项)。
{
if (errorMsg != null) errorMsg.Append(string.Format("第 {0} 题,第 {1} 个填充项未提供答案或未提供备选的错项。\r\n", i, i2));
}
else
{
for (int i3 = 1; i3 < errorItems.Length; i3++)
{
if (errorItems[i3].StartsWith("解析>>") || errorItems[i3].Length <= "错项>>".Length)
{
if (errorMsg != null) errorMsg.Append(string.Format("第 {0} 题,第 {1} 个填充项的某个错项未提供文本,或错项解析位置不正确。\r\n", i, i2));
}
}
}
}
}
}
}
else
{
if (questionTitleAndAnswerText.Contains("材料>>") == false && errorMsg != null)
{
errorMsg.Append(string.Format("第{0}题非法," + questionErrorMsg.ToString(), i));
}
}
}
}
}
if (string.IsNullOrEmpty(errorMsg.ToString())) return true;
return false;
}
}
}

Комментарий ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://gitlife.ru/oschina-mirror/lunarsf-Lunar-Markdown-Editor.git
git@gitlife.ru:oschina-mirror/lunarsf-Lunar-Markdown-Editor.git
oschina-mirror
lunarsf-Lunar-Markdown-Editor
lunarsf-Lunar-Markdown-Editor
v0.4-beta8