[英]Escape quotes for interpolated string
I have a program that generates C# from bits of C# stored in an XML file. 我有一个程序可以从存储在XML文件中的C#的位生成C#。 If I have a snippet like:
如果我有以下代码段:
foo {bar}
I need to transform that into an interpolated string, like this: 我需要将其转换为插值字符串,如下所示:
$@"foo {bar}"
The problem is that, if I have quotes outside a placeholder, eg: 问题是,如果我在占位符外部有引号,例如:
"foo" {bar}
I need to double those: 我需要将它们加倍:
$@"""foo"" {bar}"
but ignore quotes inside placeholders: 但忽略占位符内的引号:
foo {"bar"}
should produce: 应该产生:
$@"foo {"bar"}"
Also, need to look out for doubled braces: 另外,还需要注意括号是否加倍:
foo {{"bar"}}
should produce: 应该产生:
$@"foo {{""bar""}}"
And perhaps the trickiest of all, if the placeholder is preceded and/or followed by an even number of braces: 如果占位符在大括号之前和/或之后,则可能是最棘手的:
foo {{{"bar"}}}
should produce: 应该产生:
$@"foo {{{"bar"}}}"
In short, if there's a placeholder then ignore everything inside. 简而言之,如果有占位符,则忽略其中的所有内容。 For the rest of the text, double quotes.
对于其余的文本,请用双引号引起来。
Can this be accomplished using regular expressions? 可以使用正则表达式来实现吗? If not, what alternatives do I have?
如果没有,我有什么选择?
You will need at least 2 steps: 您至少需要2个步骤:
Add quotes inside the expression: 在表达式内添加引号:
"(?=[^}]*(?:}})*[^}]*$)|(?<=^[^{]*(?:{{)*)"
=> replace with ""
"(?=[^}]*(?:}})*[^}]*$)|(?<=^[^{]*(?:{{)*)"
=>替换为""
$@"..."
with string.Format("$@\\"{0}\\"", str);
string.Format("$@\\"{0}\\"", str);
括在$@"..."
string.Format("$@\\"{0}\\"", str);
Here is an IDEONE demo 这是一个IDEONE演示
var s = "\"foo\" {bar}";
var rx = new Regex(@"(?<!(?<!{){[^{}]*)""(?![^{}]*}(?!}))");
Console.WriteLine(string.Format("$@\"{0}\"",rx.Replace(s,"\"\"")));
And another demo here 还有另一个演示
This cannot be done with regular expressions. 使用正则表达式无法做到这一点。 Knowing when a placeholder starts is easy, knowing when it ends is the hard part, since a placeholder can hold almost any C# expression, so you have to keep track of blocks (
{}
) and literals (strings, chars, comments) because any brace in a literal is not significant. 知道占位符何时开始很容易,知道占位符何时结束是困难的部分,因为占位符几乎可以容纳任何C#表达式,因此您必须跟踪块(
{}
)和文字(字符串,字符,注释),因为任何在文字中大括号并不重要。
This is the code I came up with: 这是我想出的代码:
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.