/// <summary> /// Creates a transducer that replaces braces surrounding the given argument placeholder /// with <see cref="LeftBraceReplacer"/> and <see cref="RightBraceReplacer"/>. /// </summary> /// <param name="argument">The index of the argument.</param> /// <param name="argumentCount">The total number of the arguments.</param> /// <param name="transpose">Specifies whether the created transducer should be transposed (useful for backward message computation).</param> /// <returns>The created transducer.</returns> private static StringTransducer GetArgumentEscapingTransducer(int argument, int argumentCount, bool transpose) { Debug.Assert(argumentCount >= 1 && argumentCount <= 10, "Up to 10 arguments currently supported."); Debug.Assert(argument >= 0 && argument < argumentCount, "Argument index must be less than the number of arguments."); List <Pair <StringTransducer, StringTransducer> > argumentToEscapingTransducers; if (!ArgumentCountToEscapingTransducers.TryGetValue(argumentCount, out argumentToEscapingTransducers)) { argumentToEscapingTransducers = new List <Pair <StringTransducer, StringTransducer> >(argumentCount); ArgumentCountToEscapingTransducers[argumentCount] = argumentToEscapingTransducers; for (int i = 0; i < argumentCount; ++i) { // Escapes braces in {i} StringTransducer replaceBracesForDigit = StringTransducer.ConsumeElement('{'); replaceBracesForDigit.AppendInPlace(StringTransducer.ProduceElement(LeftBraceReplacer)); replaceBracesForDigit.AppendInPlace(StringTransducer.CopyElement((char)('0' + i))); replaceBracesForDigit.AppendInPlace(StringTransducer.ConsumeElement('}')); replaceBracesForDigit.AppendInPlace(StringTransducer.ProduceElement(RightBraceReplacer)); // Skips any number of placeholders which differ from {i}, with arbitrary intermediate text DiscreteChar noBraces = DiscreteChar.UniformOver('{', '}').Complement(); StringTransducer braceReplacer = StringTransducer.Copy(noBraces); if (argumentCount > 1) { // Skips every placeholder except {i} StringTransducer skipOtherDigits = StringTransducer.CopyElement('{'); skipOtherDigits.AppendInPlace(StringTransducer.CopyElement(AllDigitsExcept(i, argumentCount - 1))); skipOtherDigits.AppendInPlace(StringTransducer.CopyElement('}')); braceReplacer.AppendInPlace(skipOtherDigits); braceReplacer = StringTransducer.Repeat(braceReplacer, minTimes: 0); braceReplacer.AppendInPlace(StringTransducer.Copy(noBraces)); } // Skips placeholders, then escapes {i} and skips placeholders StringTransducer escapeAndSkip = replaceBracesForDigit.Clone(); escapeAndSkip.AppendInPlace(braceReplacer); StringTransducer transducer = braceReplacer.Clone(); transducer.AppendInPlace(escapeAndSkip); // TODO: use Optional() here if {i} can be omitted StringTransducer transducerTranspose = StringTransducer.Transpose(transducer); argumentToEscapingTransducers.Add(Pair.Create(transducer, transducerTranspose)); } } return(transpose ? argumentToEscapingTransducers[argument].Second : argumentToEscapingTransducers[argument].First); }
/// <summary> /// Initializes static members of the <see cref="StringFormatOp"/> class. /// </summary> static StringFormatOp() { DiscreteChar noBraceReplacers = DiscreteChar.UniformOver(LeftBraceReplacer, RightBraceReplacer).Complement(); DisallowBraceReplacersTransducer = StringTransducer.Copy(noBraceReplacers); }