private static void SetStyle(Attr attr, SmiStatus status) { attr.b = status.b > 0; attr.i = status.i > 0; attr.u = status.u > 0; attr.fs = (status.fs.Count > 0) ? status.fs[status.fs.Count - 1] : 0; attr.fn = (status.fn.Count > 0) ? status.fn[status.fn.Count - 1] : ""; attr.fc = (status.fc.Count > 0) ? status.fc[status.fc.Count - 1] : ""; attr.fade = (status.fade.Count > 0) ? status.fade[status.fade.Count - 1] : 0; attr.typing = (status.typing.Count > 0) ? status.typing[status.typing.Count - 1] : null; }
public static List <Attr> ToAttr(string text) { List <Attr> result = new List <Attr>(); int index = 0; int pos = 0; SmiStatus status = new SmiStatus(); Attr last = new Attr(); result.Add(last); while ((pos = text.IndexOf('<', index)) >= 0) { #region 태그명 int tagNameLength = 0; while (pos + 1 + tagNameLength < text.Length && text[pos + 1 + tagNameLength] != ' ' && text[pos + 1 + tagNameLength] != '>' && text[pos + 1 + tagNameLength] != '\r' && text[pos + 1 + tagNameLength] != '\n' && text[pos + 1 + tagNameLength] != '\t' ) { tagNameLength++; } string tagName = text.Substring(pos + 1, tagNameLength).ToUpper(); int attrPos = pos + 1 + tagNameLength; #endregion #region 태그 속성 List <string[]> attrs = new List <string[]>(); if (text[attrPos] == '>') { attrPos++; } else { if (tagName[0].Equals('/')) // 종료 태그 { attrPos = text.IndexOf('>', attrPos) + 1; } else { int mode = 0; int attrNameStart = attrPos, attrValueStart = 0; string name = ""; while (mode >= 0) { switch (mode) { case 0: // 속성 이름 { for (; mode == 0 && attrPos < text.Length; attrPos++) { switch (text[attrPos]) { case '>': if (attrPos - attrNameStart > 0) { // 이름만 있는 속성 attrs.Add(new string[] { text.Substring(attrNameStart, attrPos - attrNameStart).ToLower(), null }); } mode = -1; break; case ' ': case '\t': case '\r': case '\n': if (attrPos - attrNameStart > 0) { // 이름만 있는 속성 attrs.Add(new string[] { text.Substring(attrNameStart, attrPos - attrNameStart).ToLower(), null }); } attrNameStart = attrPos + 1; break; case '=': // 이름 끝, 값 시작 name = text.Substring(attrNameStart, attrPos - attrNameStart).ToLower(); mode = 1; attrValueStart = attrPos + 1; break; } } break; } case 1: // 속성 값 { for (; mode == 1 && attrPos < text.Length; attrPos++) { switch (text[attrPos]) { case '>': // 값 끝 attrs.Add(new string[] { name, text.Substring(attrNameStart, attrPos - attrNameStart).ToLower() }); mode = -1; attrPos++; break; case ' ': case '\t': case '\r': case '\n': // 값 끝 attrs.Add(new string[] { name, text.Substring(attrValueStart, attrPos - attrValueStart).ToLower() }); mode = 0; attrNameStart = attrPos + 1; break; case '\'': if (attrPos == attrValueStart) { mode = 2; attrValueStart++; } break; case '"': if (attrPos == attrValueStart) { mode = 3; attrValueStart++; } break; } } break; } case 2: // 속성 값 (작은 따옴표) { for (; mode == 2 && attrPos < text.Length; attrPos++) { switch (text[attrPos]) { case '\\': attrPos++; break; case '\'': // 값 끝 attrs.Add(new string[] { name, text.Substring(attrValueStart, attrPos - attrValueStart).ToLower() }); mode = 0; attrNameStart = attrPos + 1; break; } } break; } case 3: // 속성 값 (큰 따옴표) { for (; mode == 3 && attrPos < text.Length; attrPos++) { switch (text[attrPos]) { case '\\': attrPos++; break; case '"': // 값 끝 attrs.Add(new string[] { name, text.Substring(attrValueStart, attrPos - attrValueStart).ToLower() }); mode = 0; attrNameStart = attrPos + 1; break; } } break; } } } } } #endregion if (tagName[0].Equals('/')) // 종료 태그 { tagName = tagName.Substring(1); switch (tagName) { case "B": last.text += WebUtility.HtmlDecode(text.Substring(index, pos - index).Replace("\n", "")); if (last.text.Length > 0) { result.Add((last = new Attr())); } SetStyle(last, status.SetB(false)); break; case "I": last.text += WebUtility.HtmlDecode(text.Substring(index, pos - index).Replace("\n", "")); if (last.text.Length > 0) { result.Add((last = new Attr())); } SetStyle(last, status.SetI(false)); break; case "U": last.text += WebUtility.HtmlDecode(text.Substring(index, pos - index).Replace("\n", "")); if (last.text.Length > 0) { result.Add((last = new Attr())); } SetStyle(last, status.SetU(false)); break; case "FONT": last.text += WebUtility.HtmlDecode(text.Substring(index, pos - index).Replace("\n", "")); if (last.text.Length > 0) { result.Add((last = new Attr())); } SetStyle(last, status.SetFont(null)); break; default: break; } } else { switch (tagName) { case "B": last.text += WebUtility.HtmlDecode(text.Substring(index, pos - index).Replace("\n", "")); if (last.text.Length > 0) { result.Add((last = new Attr())); } SetStyle(last, status.SetB(true)); break; case "I": last.text += WebUtility.HtmlDecode(text.Substring(index, pos - index).Replace("\n", "")); if (last.text.Length > 0) { result.Add((last = new Attr())); } SetStyle(last, status.SetI(true)); break; case "U": last.text += WebUtility.HtmlDecode(text.Substring(index, pos - index).Replace("\n", "")); if (last.text.Length > 0) { result.Add((last = new Attr())); } SetStyle(last, status.SetU(true)); break; case "FONT": last.text += WebUtility.HtmlDecode(text.Substring(index, pos - index).Replace("\n", "")); if (last.text.Length > 0) { result.Add((last = new Attr())); } SetStyle(last, status.SetFont(attrs)); break; case "BR": last.text += WebUtility.HtmlDecode(text.Substring(index, pos - index).Replace("\n", "")) + "\n"; break; default: last.text += WebUtility.HtmlDecode(text.Substring(index, attrPos - index).Replace("\n", "")); break; } } index = attrPos; } last.text += WebUtility.HtmlDecode(text.Substring(index)); return(result); }