هل يمكنك اقتراح طريقة أكثر أناقة ل "رمز" C# لتنسيق HTML؟
-
04-07-2019 - |
سؤال
(هذا السؤال حول إعادة إنشاء Code ، حصلت لي على تصويت واحد ، ولكن أيضًا بعض الإجابات المثيرة للاهتمام والمفيدة. و 62 f# أسئلة من بين 32000+ على هذا الأمر يبدو بارزًا ، لذلك سأخاطر بمزيد من الرفض!)
كنت أحاول نشر القليل من التعليمات البرمجية على مدونة مدون أمس ، والتحول إلى هذا الموقع, ، والتي وجدت أنها مفيدة في الماضي. ومع ذلك ، أكل محرر المدون جميع إعلانات الأناقة ، بحيث تحول إلى طريق مسدود.
إذن (مثل أي متسلل) ، فكرت "ما مدى صعوبة أن تكون؟" ولفت بلدي في <100 سطر من f#.
فيما يلي "اللحوم" للرمز ، الذي يحول سلسلة إدخال إلى قائمة "الرموز". لاحظ أن هذه الرموز لا يجب الخلط بينها وبين الرموز الرموز على غرار Lexing/تحليل. لقد نظرت إلى هؤلاء لفترة وجيزة ، وعلى الرغم من أنني بالكاد فهمت أي شيء ، إلا أنني فهمت أنهم سيعطونني فقط الرموز ، بينما أريد الاحتفاظ بسلسلة أصلية.
والسؤال هو: هل هناك طريقة أكثر أناقة للقيام بذلك؟ لا أحب إعادة تعريف n من S المطلوبة لإزالة كل سلسلة رمزية من سلسلة الإدخال ، ولكن من الصعب تقسيم السلسلة إلى الرموز المحتملة مقدمًا ، بسبب أشياء مثل التعليقات والسلاسل وتوجيه #Region (والتي يحتوي على شخصية غير كلمة).
//Types of tokens we are going to detect
type Token =
| Whitespace of string
| Comment of string
| Strng of string
| Keyword of string
| Text of string
| EOF
//turn a string into a list of recognised tokens
let tokenize (s:String) =
//this is the 'parser' - should we look at compiling the regexs in advance?
let nexttoken (st:String) =
match st with
| st when Regex.IsMatch(st, "^\s+") -> Whitespace(Regex.Match(st, "^\s+").Value)
| st when Regex.IsMatch(st, "^//.*?\r?\n") -> Comment(Regex.Match(st, "^//.*?\r?\n").Value) //this is double slash-style comments
| st when Regex.IsMatch(st, "^/\*(.|[\r?\n])*?\*/") -> Comment(Regex.Match(st, "^/\*(.|[\r?\n])*?\*/").Value) // /* */ style comments http://ostermiller.org/findcomment.html
| st when Regex.IsMatch(st, @"^""([^""\\]|\\.|"""")*""") -> Strng(Regex.Match(st, @"^""([^""\\]|\\.|"""")*""").Value) // unescaped = "([^"\\]|\\.|"")*" http://wordaligned.org/articles/string-literals-and-regular-expressions
| st when Regex.IsMatch(st, "^#(end)?region") -> Keyword(Regex.Match(st, "^#(end)?region").Value)
| st when st <> "" ->
match Regex.Match(st, @"^[^""\s]*").Value with //all text until next whitespace or quote (this may be wrong)
| x when iskeyword x -> Keyword(x) //iskeyword uses Microsoft.CSharp.CSharpCodeProvider.IsValidIdentifier - a bit fragile...
| x -> Text(x)
| _ -> EOF
//tail-recursive use of next token to transform string into token list
let tokeneater s =
let rec loop s acc =
let t = nexttoken s
match t with
| EOF -> List.rev acc //return accumulator (have to reverse it because built backwards with tail recursion)
| Whitespace(x) | Comment(x)
| Keyword(x) | Text(x) | Strng(x) ->
loop (s.Remove(0, x.Length)) (t::acc) //tail recursive
loop s []
tokeneater s
(إذا كان أي شخص مهتمًا حقًا ، يسعدني نشر بقية الكود)
تعديلباستخدام اقتراح ممتاز من الأنماط النشطة بواسطة KVB ، يبدو البت المركزي هكذا ، أفضل بكثير!
let nexttoken (st:String) =
match st with
| Matches "^\s+" s -> Whitespace(s)
| Matches "^//.*?\r?(\n|$)" s -> Comment(s) //this is double slash-style comments
| Matches "^/\*(.|[\r?\n])*?\*/" s -> Comment(s) // /* */ style comments http://ostermiller.org/findcomment.html
| Matches @"^@?""([^""\\]|\\.|"""")*""" s -> Strng(s) // unescaped regexp = ^@?"([^"\\]|\\.|"")*" http://wordaligned.org/articles/string-literals-and-regular-expressions
| Matches "^#(end)?region" s -> Keyword(s)
| Matches @"^[^""\s]+" s -> //all text until next whitespace or quote (this may be wrong)
match s with
| IsKeyword x -> Keyword(s)
| _ -> Text(s)
| _ -> EOF
المحلول
كنت أستخدم نمطًا نشطًا لتغليف أزواج regex.ismatch و regex.match ، مثل ذلك:
let (|Matches|_|) re s =
let m = Regex(re).Match(s)
if m.Success then
Some(Matches (m.Value))
else
None
ثم يمكن أن تبدو وظيفتك التالية:
let nexttoken (st:String) =
match st with
| Matches "^s+" s -> Whitespace(s)
| Matches "^//.*?\r?\n" s -> Comment(s)
...