[英]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個步驟:
在表達式內添加引號:
"(?=[^}]*(?:}})*[^}]*$)|(?<=^[^{]*(?:{{)*)"
=>替換為""
觀看演示
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.