루프 :어떻게이 루프를 빠르게 할 수 있습니까? 한 번에 여러 용어를 대체하는 수업이 있습니까?
var pattern = _dict[key];
string before;
do
{
before = pattern;
foreach (var pair in _dict)
if (key != pair.Key)
pattern = pattern.Replace(string.Concat("{", pair.Key, "}"), string.Concat("(", pair.Value, ")"));
} while (pattern != before);
return pattern;
그냥 않는 키의 무리에서 찾기 및 바꾸기를 반복했다. 사전은 단지 <string,string>
입니다.
이 두 가지 개선 사항을 확인할 수 있습니다.
- 언제든지
pattern.Replace
문자열의 처음부터 다시 검색합니다. 첫 번째{
을 눌렀을 때 (아마도 바이너리 검색을 사용하여) 일치하는 키 목록을 살펴본 다음 해당 키를 바꾸는 것이 더 좋을 것입니다. pattern != before
비트는 반복하는 동안 바뀐 것이 있는지 확인하는 방법입니다.pattern.Replace
함수가 실제로 얼마나 많은 대체물이 반환되었거나 실제로 대체 된 경우 대체물이 필요하지 않을 것입니다.
그러나 ... 나는 모든 것을하기 위해 큰 불쾌한 것을 쓰고 싶지 않습니다. 이는 매우 일반적인 시나리오 여야합니다. 존재하는 솔루션이 있습니까? 이었다는으로 서 및 에
전체 클래스
감사 ChrisWue.
class FlexDict : IEnumerable<KeyValuePair<string,string>>
{
private Dictionary<string, string> _dict = new Dictionary<string, string>();
private static readonly Regex _re = new Regex(@"{([_a-z][_a-z0-9-]*)}", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public void Add(string key, string pattern)
{
_dict[key] = pattern;
}
public string Expand(string pattern)
{
pattern = _re.Replace(pattern, match =>
{
string key = match.Groups[1].Value;
if (_dict.ContainsKey(key))
return "(" + Expand(_dict[key]) + ")";
return match.Value;
});
return pattern;
}
public string this[string key]
{
get { return Expand(_dict[key]); }
}
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
{
foreach (var p in _dict)
yield return new KeyValuePair<string,string>(p.Key, this[p.Key]);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
서로를 연장 할 수 복잡한 정규 표현식을 구축 예를 들어 사용
class Program
{
static void Main(string[] args)
{
var flex = new FlexDict
{
{"h", @"[0-9a-f]"},
{"nonascii", @"[\200-\377]"},
{"unicode", @"\\{h}{1,6}(\r\n|[ \t\r\n\f])?"},
{"escape", @"{unicode}|\\[^\r\n\f0-9a-f]"},
{"nmstart", @"[_a-z]|{nonascii}|{escape}"},
{"nmchar", @"[_a-z0-9-]|{nonascii}|{escape}"},
{"string1", @"""([^\n\r\f\\""]|\\{nl}|{escape})*"""},
{"string2", @"'([^\n\r\f\\']|\\{nl}|{escape})*'"},
{"badstring1", @"""([^\n\r\f\\""]|\\{nl}|{escape})*\\?"},
{"badstring2", @"'([^\n\r\f\\']|\\{nl}|{escape})*\\?"},
{"badcomment1", @"/\*[^*]*\*+([^/*][^*]*\*+)*"},
{"badcomment2", @"/\*[^*]*(\*+[^/*][^*]*)*"},
{"baduri1", @"url\({w}([!#$%&*-\[\]-~]|{nonascii}|{escape})*{w}"},
{"baduri2", @"url\({w}{string}{w}"},
{"baduri3", @"url\({w}{badstring}"},
{"comment", @"/\*[^*]*\*+([^/*][^*]*\*+)*/"},
{"ident", @"-?{nmstart}{nmchar}*"},
{"name", @"{nmchar}+"},
{"num", @"[0-9]+|[0-9]*\.[0-9]+"},
{"string", @"{string1}|{string2}"},
{"badstring", @"{badstring1}|{badstring2}"},
{"badcomment", @"{badcomment1}|{badcomment2}"},
{"baduri", @"{baduri1}|{baduri2}|{baduri3}"},
{"url", @"([!#$%&*-~]|{nonascii}|{escape})*"},
{"s", @"[ \t\r\n\f]+"},
{"w", @"{s}?"},
{"nl", @"\n|\r\n|\r|\f"},
{"A", @"a|\\0{0,4}(41|61)(\r\n|[ \t\r\n\f])?"},
{"C", @"c|\\0{0,4}(43|63)(\r\n|[ \t\r\n\f])?"},
{"D", @"d|\\0{0,4}(44|64)(\r\n|[ \t\r\n\f])?"},
{"E", @"e|\\0{0,4}(45|65)(\r\n|[ \t\r\n\f])?"},
{"G", @"g|\\0{0,4}(47|67)(\r\n|[ \t\r\n\f])?|\\g"},
{"H", @"h|\\0{0,4}(48|68)(\r\n|[ \t\r\n\f])?|\\h"},
{"I", @"i|\\0{0,4}(49|69)(\r\n|[ \t\r\n\f])?|\\i"},
{"K", @"k|\\0{0,4}(4b|6b)(\r\n|[ \t\r\n\f])?|\\k"},
{"L", @"l|\\0{0,4}(4c|6c)(\r\n|[ \t\r\n\f])?|\\l"},
{"M", @"m|\\0{0,4}(4d|6d)(\r\n|[ \t\r\n\f])?|\\m"},
{"N", @"n|\\0{0,4}(4e|6e)(\r\n|[ \t\r\n\f])?|\\n"},
{"O", @"o|\\0{0,4}(4f|6f)(\r\n|[ \t\r\n\f])?|\\o"},
{"P", @"p|\\0{0,4}(50|70)(\r\n|[ \t\r\n\f])?|\\p"},
{"R", @"r|\\0{0,4}(52|72)(\r\n|[ \t\r\n\f])?|\\r"},
{"S", @"s|\\0{0,4}(53|73)(\r\n|[ \t\r\n\f])?|\\s"},
{"T", @"t|\\0{0,4}(54|74)(\r\n|[ \t\r\n\f])?|\\t"},
{"U", @"u|\\0{0,4}(55|75)(\r\n|[ \t\r\n\f])?|\\u"},
{"X", @"x|\\0{0,4}(58|78)(\r\n|[ \t\r\n\f])?|\\x"},
{"Z", @"z|\\0{0,4}(5a|7a)(\r\n|[ \t\r\n\f])?|\\z"},
{"Z", @"z|\\0{0,4}(5a|7a)(\r\n|[ \t\r\n\f])?|\\z"},
{"CDO", @"<!--"},
{"CDC", @"-->"},
{"INCLUDES", @"~="},
{"DASHMATCH", @"\|="},
{"STRING", @"{string}"},
{"BAD_STRING", @"{badstring}"},
{"IDENT", @"{ident}"},
{"HASH", @"#{name}"},
{"IMPORT_SYM", @"@{I}{M}{P}{O}{R}{T}"},
{"PAGE_SYM", @"@{P}{A}{G}{E}"},
{"MEDIA_SYM", @"@{M}{E}{D}{I}{A}"},
{"CHARSET_SYM", @"@charset\b"},
{"IMPORTANT_SYM", @"!({w}|{comment})*{I}{M}{P}{O}{R}{T}{A}{N}{T}"},
{"EMS", @"{num}{E}{M}"},
{"EXS", @"{num}{E}{X}"},
{"LENGTH", @"{num}({P}{X}|{C}{M}|{M}{M}|{I}{N}|{P}{T}|{P}{C})"},
{"ANGLE", @"{num}({D}{E}{G}|{R}{A}{D}|{G}{R}{A}{D})"},
{"TIME", @"{num}({M}{S}|{S})"},
{"PERCENTAGE", @"{num}%"},
{"NUMBER", @"{num}"},
{"URI", @"{U}{R}{L}\({w}{string}{w}\)|{U}{R}{L}\({w}{url}{w}\)"},
{"BAD_URI", @"{baduri}"},
{"FUNCTION", @"{ident}\("},
};
var testStrings = new[] { @"""str""", @"'str'", "5", "5.", "5.0", "a", "alpha", "url(hello)",
"url(\"hello\")", "url(\"blah)", @"\g", @"/*comment*/", @"/**/", @"<!--", @"-->", @"~=",
"|=", @"#hash", "@import", "@page", "@media", "@charset", "!/*iehack*/important"};
foreach (var pair in flex)
{
Console.WriteLine("{0}\n\t{1}\n", pair.Key, pair.Value);
}
var sw = Stopwatch.StartNew();
foreach (var str in testStrings)
{
Console.WriteLine("{0} matches: ", str);
foreach (var pair in flex)
{
if (Regex.IsMatch(str, "^(" + pair.Value + ")$", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture))
Console.WriteLine(" {0}", pair.Key);
}
}
Console.WriteLine("\nRan in {0} ms", sw.ElapsedMilliseconds);
Console.ReadLine();
}
}
목적
. 즉, the css spec을 구현하려고합니다.
예, 값에 다른 {자리 표시 자}가 있습니다. 아니요, 저는 무한 루프에 갇히지 않을 것이라고 확신 할 수 없습니다 ...'key! = pair.Key'는 그것을 방지하기로되어 있었지만 (어쨌든 w를 바꾸는 것), 여러분이 지적했듯이 다른 방법으로 발생할 수 있습니다. 나는 너무 걱정하지 않는다 ... 무한 루프가 만들어지면, 그것은 빨리 분명해진다. – mpen
추가 개선 사항은 루프 대신 재귀 적으로 만드는 것일 수 있습니다. 위의 대체 코드가 Replace (s, re, dict)라는 함수라고 가정하면 'return'("+ Replace (_dict [matchKey], re, _dict) +") "" '중첩의 양과 길이에 따라 소스 문자열 중 더 많은 것을 향상시킬 수 있습니다. 무한 루프가 아닌 stackoverflow에서 실행되는 "이점"이 있습니다. 또한 정규 표현식을 미리 컴파일하는 것이 도움이 될 수 있습니다. – ChrisWue
@ChrisWue : 나는 그것을 재귀 적으로 만들 수 있다고 생각하지 않습니다 (업데이트 된 질문 참조). 내가 설정 한 방식대로, 특정 키에 대한 패턴을 반환하지만, 입력 문자열을 받아들이지 않습니다 ... 실제로 .. 몇 가지 수정을 통해이를 수행 할 수 있습니다. Q를 다시 업데이트 중입니다. – mpen