Multiline String Literal in C#
有没有一种简单的方法可以用C创建多行字符串?
我现在有:
1 2 3 | string query ="SELECT foo, bar" +" FROM table" +" WHERE id = 42"; |
我知道PHP有
1 2 3 | <<<BLOCK BLOCK; |
C有类似的东西吗?
可以在
1 2 3 | string query = @"SELECT foo, bar FROM table WHERE id = 42"; |
在使用此方法时,您也不必转义特殊字符,除了jon skeet的答案中所示的双引号。
它在C中称为逐字字符串文字,它只是将@放在文字之前的问题。这不仅允许多行,而且还关闭了转义。例如,您可以:
1 2 3 | string query = @"SELECT foo, bar FROM table WHERE name = 'a\b'"; |
唯一的转义是,如果您想要双引号,则必须添加一个额外的双引号符号:
1 | string quote = @"Jon said,""This will work,"" - and it did!"; |
另一个需要注意的是使用string.format中的字符串文本。在这种情况下,您需要转义大括号/方括号""和""。
1 2 3 4 5 6 | // this would give a format exception string.Format(@" function test(x) { return x * {0} }", aMagicValue) // this contrived example would work string.Format(@" function test(x) {{ return x * {0} }}", aMagicValue) |
我发现使用字符串文字的问题是,它会使代码看起来有点"奇怪",因为为了不在字符串本身中获得空格,必须完全保持对齐:
1 2 3 4 | var someString = @"The quick brown fox..."; |
讨厌。
所以我喜欢使用的解决方案是:
1 2 3 4 5 6 | var someString = String.Join( Environment.NewLine, "The", "quick", "brown", "fox..."); |
当然,如果您只想像现在这样逻辑地拆分SQL语句的行,而实际上不需要新行,那么您可以用
作为补充说明,使用C 6.0,现在可以将插入字符串与逐字字符串文字组合在一起:
1 2 3 4 5 6 7 | string camlCondition = $@" <Where> <Contains> <FieldRef Name='Resource'/> <Value Type='Text'>{(string)parameter}</Value> </Contains> </Where>"; |
为什么人们总是混淆字符串和字符串文字?接受的答案是对另一个问题的一个很好的答案,而不是对这个问题。
我知道这是一个古老的话题,但我来到这里的时候,可能有一个和《行动纲领》相同的问题,看到人们总是误读它,真令人沮丧。或者是我读错了,我不知道。
大致来说,字符串是计算机内存中的一个区域,在程序执行期间,它包含一系列可以映射到文本字符的字节。另一方面,字符串文字是一段尚未编译的源代码,它表示在随后的程序执行过程中用于初始化字符串的值。
在C中,语句…
1 2 3 | string query ="SELECT foo, bar" +" FROM table" +" WHERE id = 42"; |
…不生成三行字符串,只生成一行字符串;三个字符串(每个字符串都由不同的文本初始化)的串联不包含新行修饰符。
操作程序似乎要问的不是如何在编译后的字符串中引入类似于源代码中发现的换行符,而是如何在源代码中分解一行长的文本而不引入编译后的字符串中的换行符,以便清晰明了。在不需要延长执行时间的情况下,将来自源代码的多个子字符串连接起来。就像JavaScript或C++中的多行字符串文本中的尾随反斜杠。
建议使用逐字字符串,不允许使用
据我所知,C没有(至少在我仍在使用的旧石器时代版本中,从上个十年开始)干净地生成可以在编译期间而不是执行期间解决的多行字符串文本的功能。
也许当前的版本确实支持它,但我想我会分享我在字符串和字符串文本之间所感知到的差异。
我没有看到这个,所以我会把它贴在这里(如果你有兴趣传递一个字符串,你也可以这样做。)你的想法是,你可以把字符串分解成多行,并以任何方式添加你自己的内容(也可以是多行)。这里"tablename"可以传递到字符串中。
1 2 3 4 5 6 7 8 9 10 11 12 | private string createTableQuery =""; void createTable(string tableName) { createTableQuery = @"CREATE TABLE IF NOT EXISTS ["+ tableName + @"] ( [ID] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, [Key] NVARCHAR(2048) NULL, [Value] VARCHAR(2048) NULL )"; } |
您可以使用@和""。
1 2 3 4 5 6 7 8 9 10 11 12 | string sourse = @"{ ""items"":[ { ""itemId"":0, ""name"":""item0"" }, { ""itemId"":1, ""name"":""item1"" } ] }"; |
是的,您可以将一个字符串拆分为多行,而不必在实际字符串中引入换行符,但它并不漂亮:
1 2 3 4 | string s = $@"This string{ string.Empty} contains no newlines{ string.Empty} even though it is spread onto{ string.Empty} multiple lines."; |
技巧是引入计算结果为空的代码,并且该代码可能包含换行符,而不会影响输出。我根据这个答案对一个类似的问题采用了这种方法。
对于问题是什么,显然有一些混淆,但有两个提示,我们在这里想要的是一个不包含任何换行符的字符串文字,它的定义跨越多行。(在评论中,他这样说,"这是我所拥有的",显示了不创建包含换行符的字符串的代码)
此单元测试显示的目的是:
1 2 3 4 5 6 7 | [TestMethod] public void StringLiteralDoesNotContainSpaces() { string query ="hi" +"there"; Assert.AreEqual("hithere", query); } |
更改上面的查询定义,使其为一个字符串文本,而不是由编译器将两个字符串文本串联成一个字符串文本。
C++方法是用反斜杠结束每行,使换行符被释放,而不会出现在输出中。不幸的是,仍然存在这样一个问题:第一行之后的每一行必须保持对齐,以便不向结果添加额外的空白。
只有一个选项不依赖可能不会发生的编译器优化,那就是将定义放在一行上。如果你想依靠编译器的优化,你已经拥有的+是很好的;你不需要左对齐字符串,你不会得到换行结果,它只是一个操作,没有函数调用,期望优化。
如果不需要空格/换行符,则添加字符串似乎有效:
1 2 3 4 5 6 7 8 9 | var myString = String.Format( "hello" + "world" + " i am {0}" + " and I like {1}.", animalType, animalPreferenceType ); // hello world i am a pony and I like other ponies. |
如果你愿意的话,你可以在这里运行上面的程序。
您可以使用这两种方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | private static String ReverseString(String str) { int word_length = 0; String result =""; for (int i = 0; i < str.Length; i++) { if (str[i] == ' ') { result ="" + result; word_length = 0; } else { result = result.Insert(word_length, str[i].ToString()); word_length++; } } return result; } //NASSIM LOUCHANI public static string SplitLineToMultiline(string input, int rowLength) { StringBuilder result = new StringBuilder(); StringBuilder line = new StringBuilder(); Stack<string> stack = new Stack<string>(ReverseString(input).Split(' ')); while (stack.Count > 0) { var word = stack.Pop(); if (word.Length > rowLength) { string head = word.Substring(0, rowLength); string tail = word.Substring(rowLength); word = head; stack.Push(tail); } if (line.Length + word.Length > rowLength) { result.AppendLine(line.ToString()); line.Clear(); } line.Append(word +""); } result.Append(line); return result.ToString(); } |
在splitlinetomultiline()中,需要定义要使用的字符串和行长度,这非常简单。谢谢您。