簡體   English   中英

插值字符串的轉義引號

[英]Escape quotes for interpolated string

我有一個程序可以從存儲在XML文件中的C#的位生成C#。 如果我有以下代碼段:

foo {bar}

我需要將其轉換為插值字符串,如下所示:

$@"foo {bar}"

問題是,如果我在占位符外部有引號,例如:

"foo" {bar}

我需要將它們加倍:

$@"""foo"" {bar}"

但忽略占位符內的引號:

foo {"bar"}

應該產生:

$@"foo {"bar"}"

另外,還需要注意括號是否加倍:

foo {{"bar"}}

應該產生:

$@"foo {{""bar""}}"

如果占位符在大括號之前和/或之后,則可能是最棘手的:

foo {{{"bar"}}}

應該產生:

$@"foo {{{"bar"}}}"

簡而言之,如果有占位符,則忽略其中的所有內容。 對於其余的文本,請用雙引號引起來。

可以使用正則表達式來實現嗎? 如果沒有,我有什么選擇?

您至少需要2個步驟:

  1. 在表達式內添加引號:

    "(?=[^}]*(?:}})*[^}]*$)|(?<=^[^{]*(?:{{)*)" =>替換為""

觀看演示

  1. string.Format("$@\\"{0}\\"", str);括在$@"..." string.Format("$@\\"{0}\\"", str);

這是一個IDEONE演示

var s = "\"foo\" {bar}";
var rx = new Regex(@"(?<!(?<!{){[^{}]*)""(?![^{}]*}(?!}))");
Console.WriteLine(string.Format("$@\"{0}\"",rx.Replace(s,"\"\"")));

還有另一個演示

使用正則表達式無法做到這一點。 知道占位符何時開始很容易,知道占位符何時結束是困難的部分,因為占位符幾乎可以容納任何C#表達式,因此您必須跟蹤塊( {} )和文字(字符串,字符,注釋),因為任何在文字中大括號並不重要。

這是我想出的代碼:

enum ParsingMode {
   Text,
   Code,
   InterpolatedString,
   InterpolatedVerbatimString,
   String,
   VerbatimString,
   Char,
   MultilineComment
}

public static string EscapeValueTemplate(string valueTemplate) {

   if (valueTemplate == null) throw new ArgumentNullException(nameof(valueTemplate));

   var quoteIndexes = new List<int>();

   var modeStack = new Stack<ParsingMode>();
   modeStack.Push(ParsingMode.Text);

   Func<ParsingMode> currentMode = () => modeStack.Peek();

   for (int i = 0; i < valueTemplate.Length; i++) {

      char c = valueTemplate[i];
      Func<char?> nextChar = () =>
         i + 1 < valueTemplate.Length ? valueTemplate[i + 1]
         : default(char?);

      switch (currentMode()) {
         case ParsingMode.Code:
            switch (c) {
               case '{':
                  modeStack.Push(ParsingMode.Code);
                  break;

               case '}':
                  modeStack.Pop();
                  break;

               case '\'':
                  modeStack.Push(ParsingMode.Char);
                  break;

               case '"':
                  ParsingMode stringMode = ParsingMode.String;

                  switch (valueTemplate[i - 1]) {
                     case '@':
                        if (i - 2 >= 0 && valueTemplate[i - 2] == '$') {
                           stringMode = ParsingMode.InterpolatedVerbatimString;
                        } else {
                           stringMode = ParsingMode.VerbatimString;
                        }
                        break;

                     case '$':
                        stringMode = ParsingMode.InterpolatedString;
                        break;
                  }

                  modeStack.Push(stringMode);
                  break;

               case '/':
                  if (nextChar() == '*') {
                     modeStack.Push(ParsingMode.MultilineComment);
                     i++;
                  }
                  break;
            }
            break;

         case ParsingMode.Text:
         case ParsingMode.InterpolatedString:
         case ParsingMode.InterpolatedVerbatimString:
            switch (c) {
               case '{':
                  if (nextChar() == '{') {
                     i++;
                  } else {
                     modeStack.Push(ParsingMode.Code);
                  }
                  break;

               case '"':
                  switch (currentMode()) {
                     case ParsingMode.Text:
                        quoteIndexes.Add(i);
                        break;

                     case ParsingMode.InterpolatedString:
                        modeStack.Pop();
                        break;

                     case ParsingMode.InterpolatedVerbatimString:
                        if (nextChar() == '"') {
                           i++;
                        } else {
                           modeStack.Pop();
                        }
                        break;
                  }
                  break;

               case '\\':
                  if (currentMode() == ParsingMode.InterpolatedString) {
                     i++;
                  }
                  break;
            }
            break;

         case ParsingMode.String:
            switch (c) {
               case '\\':
                  i++;
                  break;

               case '"':
                  modeStack.Pop();
                  break;
            }
            break;

         case ParsingMode.VerbatimString:
            if (c == '"') {
               if (nextChar() == '"') {
                  i++;
               } else {
                  modeStack.Pop();
               }
            }
            break;

         case ParsingMode.Char:
            switch (c) {
               case '\\':
                  i++;
                  break;
               case '\'':
                  modeStack.Pop();
                  break;
            }
            break;

         case ParsingMode.MultilineComment:
            if (c == '*') {
               if (nextChar() == '/') {
                  modeStack.Pop();
                  i++;
               }
            }
            break;
      }
   }

   var sb = new StringBuilder(valueTemplate, valueTemplate.Length + quoteIndexes.Count);

   for (int i = 0; i < quoteIndexes.Count; i++) {
      sb.Insert(quoteIndexes[i] + i, '"');
   }

   return sb.ToString();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM