diff --git a/src/SmartFormat.Tests/Extensions/DictionaryFormatterTests.cs b/src/SmartFormat.Tests/Extensions/DictionaryFormatterTests.cs index 29930403..d0689203 100644 --- a/src/SmartFormat.Tests/Extensions/DictionaryFormatterTests.cs +++ b/src/SmartFormat.Tests/Extensions/DictionaryFormatterTests.cs @@ -26,6 +26,7 @@ public object[] GetArgs() {"A", "a"}, {"B", "b"}, {"C", "c"}, + {"Name.with.dot", "d"} }}, {"Object", new { Prop1 = "a", @@ -60,11 +61,13 @@ public void Test_Dictionary() var formats = new string[] { "Chained: {0.Numbers.One} {Numbers.Two} {Letters.A} {Object.Prop1} ", - "Nested: {0:{Numbers:{One} {Two}} } {Letters:{A}} {Object:{Prop1}} ", // Due to double-brace escaping, the spacing in this nested format is irregular + "Nested: {0:{Numbers:{One} {Two}} } {Letters:{A}} {Letters:{Name.with.dot}} {Object:{Prop1}} ", // Due to double-brace escaping, the spacing in this nested format is irregular + @"{Letters.`Name.with.dot`}", // Due to double-brace escaping, the spacing in this nested format is irregular }; var expected = new string[] { "Chained: 1 2 a a ", - "Nested: 1 2 a a ", + "Nested: 1 2 a d a ", + "d", }; var args = GetArgs(); formatter.Test(formats, args, expected); diff --git a/src/SmartFormat/Core/Parsing/Parser.cs b/src/SmartFormat/Core/Parsing/Parser.cs index 4312b565..f7fcb7cd 100644 --- a/src/SmartFormat/Core/Parsing/Parser.cs +++ b/src/SmartFormat/Core/Parsing/Parser.cs @@ -54,6 +54,7 @@ public Parser(ErrorAction errorAction) /// private char AlternativeEscapeChar = '\\'; + private char QuoteChar = '`'; /// /// Includes a-z and A-Z in the list of allowed selector chars. /// @@ -132,22 +133,27 @@ public Format ParseFormat(string format) int lastI = 0; int operatorIndex = 0; int selectorIndex = 0; + bool inQuotedText = false; + char lastChar = (char)0; + char c = (char)0; for (int i = 0, length = format.Length; i < length; i++) { - var c = format[i]; + lastChar = c; + c = format[i]; if (currentPlaceholder == null) { if (c == '{') { + var startIndex = i; // Finish the last text item: if (i != lastI) current.Items.Add(new LiteralText(current, lastI) { endIndex = i }); lastI = i + 1; + var nextI = lastI; // See if this brace should be escaped: if (!this.AlternativeEscaping) { - var nextI = lastI; if (nextI < length && format[nextI] == '{') { i++; @@ -155,9 +161,15 @@ public Format ParseFormat(string format) } } + if( nextI < length && format[nextI] == QuoteChar ) + { + inQuotedText = true; + i++; + lastI++; + } // New placeholder: nestedDepth++; - currentPlaceholder = new Placeholder(current, i, nestedDepth); + currentPlaceholder = new Placeholder( current, startIndex, nestedDepth ); current.Items.Add(currentPlaceholder); current.HasNested = true; operatorIndex = i+1; @@ -212,23 +224,40 @@ public Format ParseFormat(string format) else { // Placeholder is NOT null, so that means we're parsing the selectors: + if( inQuotedText ) + { + inQuotedText = c != QuoteChar; + } + else + { + var endIndex = i; + if( i > 0 && lastChar == QuoteChar ) + { + endIndex = i-1; + } if (Operators.IndexOf(c) != -1) { // Add the selector: if (i != lastI) { - currentPlaceholder.Selectors.Add(new Selector(format, lastI, i, operatorIndex, selectorIndex)); + currentPlaceholder.Selectors.Add( new Selector( format, lastI, endIndex, operatorIndex, selectorIndex ) ); selectorIndex++; operatorIndex = i; } lastI = i + 1; + if( lastI < length && format[lastI] == QuoteChar ) + { + inQuotedText = true; + i++; + lastI++; } + } else if (c == ':') { // Add the selector: if (i != lastI) - currentPlaceholder.Selectors.Add(new Selector(format, lastI, i, operatorIndex, selectorIndex)); + currentPlaceholder.Selectors.Add( new Selector( format, lastI, endIndex, operatorIndex, selectorIndex ) ); else if (operatorIndex != i) { // There are trailing operators. For now, this is an error. @@ -247,7 +276,7 @@ public Format ParseFormat(string format) { // Add the selector: if (i != lastI) - currentPlaceholder.Selectors.Add(new Selector(format, lastI, i, operatorIndex, selectorIndex)); + currentPlaceholder.Selectors.Add( new Selector( format, lastI, endIndex, operatorIndex, selectorIndex ) ); else if (operatorIndex != i) { // There are trailing operators. For now, this is an error. @@ -261,6 +290,7 @@ public Format ParseFormat(string format) currentPlaceholder.endIndex = i + 1; current = currentPlaceholder.parent; currentPlaceholder = null; + inQuotedText = false; } else { @@ -275,6 +305,7 @@ public Format ParseFormat(string format) // Invalid character in the selector. parsingErrors.AddIssue(current, "Invalid character in the selector", i, i + 1); //ParserError(format, i, "Invalid character in the selector", result); + } } } }