C + + 11的原始字符串字面值 R“(...)”中括号的基本原理是什么?

C + + 11中引入了一个非常方便的特性,称为原始字符串文字,它是没有转义字符的字符串。而不是这样写:

  regex mask("\\t[0-9]+\\.[0-9]+\\t\\\\SUB");

你可以这样写:

  regex mask(R"(\t[0-9]+\.[0-9]+\t\\SUB)");

更具可读性。但是,注意在字符串周围必须放置额外的括号来定义一个原始字符串文字。

我的问题是,我们为什么需要这些?对我来说,它看起来相当丑陋和不合逻辑。以下是我看到的缺点:

  • 额外的冗长,而整个特性是用来使文字更紧凑
  • 很难区分文字的主体和定义符号

这就是我所说的难以区分的:

"good old usual string literal"
^-    body inside quotes   -^


R"(new strange raw string literal)"
^- body inside parenthesis  -^

这里是专家:

  • 更灵活,原始字符串中可用的字符更多,特别是与分隔符 "delim( can use "()" here )delim"一起使用时

但是,如果需要更多的灵活性,可以使用老式的、可转义的字符串文字。为什么标准委员会决定用这些绝对不必要的括号来污染每个原始字符串文字的内容?这背后的理由是什么?我没提到的优点是什么?

克雷克的答案很棒,但不幸的是,这不是一个答案。因为我已经描述过了,所以我理解它是如何工作的,以及它带来了什么好处。从我问这个问题到现在已经过去五年了,仍然没有答案。我仍然对这个决定感到沮丧。有人可能会说这是品味的问题,但我不同意。你使用多少空格,你如何命名你的变量,是 SomeFunction()还是 some_function()-这是味道的问题。我可以很容易地从一种风格转换到另一种风格。

But this?.. Still feels awkward and clumsy after so many years. No, this is not about the taste. This is about how we want to cover all possible cases no matter what. We doomed to write these ugly parens every time we need to write a Windows-specific path, or a regular expression, or a multi-line string literal. And for what?.. For those rare cases when we actually need to put " in a string? I wish I was on that committee meeting where they decided to do it this way. And I would be strongly against this really bad decision. I wish. Now we are doomed.

谢谢你读了这么久,现在我感觉好多了。

UPD2 以下是我的备选方案,我认为这两个方案都比现有的方案要好得多。

建议1。受 python 启发。不支持带三重引号的字符串: R"""Here is a string literal with any content, except for triple quotes, which you don't actually use that often."""

建议2。受常识启发。支持所有可能的字符串文字,就像当前的字符串文字一样: R"delim"content of string"delim"。使用空分隔符: R""Looks better, doesn't it?""。空的原始字符串: R""""。带双引号的原始字符串: R"#"Here are double quotes: "", thanks"#"

这些提案有什么问题吗?

27307 次浏览

括号的作用是允许您指定自定义分隔符:

R"foo(Hello World)foo"   // the string "Hello World"

在您的示例中,在典型的使用中,分隔符仅为空,因此原始字符串由序列 R"()"封装。

允许使用任意的分隔符是一种设计决策,它反映了提供完整解决方案的愿望,没有奇怪的限制或边界情况。可以选择字符串中没有出现的 任何字符序列作为分隔符。

如果没有这个属性,那么如果字符串本身包含类似 "(如果您只需要 R"..."作为原始字符串语法)或 )"(如果分隔符为空)的内容,那么您就会遇到麻烦。这两种情况都是非常常见和频繁的字符序列,特别是在正则表达式中,所以如果决定是否使用原始字符串取决于字符串的特定内容,那将是非常恼人的。

请记住,在原始字符串中没有其他转义机制,因此您所能做的最好的事情就是将字符串文字的片段连接起来,这将是非常不切实际的。通过允许自定义分隔符,所有您需要做的就是选择一个不寻常的字符序列一次,并且 也许吧修改它在非常罕见的情况下,当您进行未来的编辑。

但是再次强调,即使是空分隔符也已经很有用了,因为 R"(...)"语法允许在字符串中放置裸引号。这本身就是一个很大的收获。

正如另一个答案所解释的那样,在 ")",或者实际上在字符串本身中可能出现的任何结束序列的情况下,引号必须有一些附加的内容,以避免解析不明确。

至于语法选择,我同意语法选择是 不太理想,但一般来说还可以(您可以想到: “ things could be bad”,lol)。我认为这是使用简单性和解析简单性之间的一个很好的折衷。

建议1 。受 python 启发。不能使用 三重引号:
“任何内容,除了三重引号” 并不经常使用

这里确实存在一个问题——“引号,你实际上并不经常使用”。 首先,原始字符串的概念就是表示 生的字符串,也就是说,不管字符串的内容是什么,它们都与文本文件中的字符串完全一样,不需要对字符串进行 任何修改。其次,语法应该是通用的,即不要添加“几乎原始的字符串”等变体。

如何用这种语法写一个引号?引用两句?注意——这些是非常常见的情况,特别是当您的代码处理字符串和解析时。

建议2。
字符串的内容。
“看起来好多了,不是吗?”。
下面是双引号: “谢谢”。

这个可能是更好的候选人。但是有一件事——一个常见的情况(我相信这是一个激励人们接受语法的情况) ,那就是双引号字符本身是 非常常见的,原始字符串对于这些情况应该很有用。

那么,让我们看看,正常的字符串语法:

s1 = "\"";
s2 = "\"quoted string\"";

你的语法,例如“ x”作为 delim:

s1 = R"x"""x";
s2 = R"x""quoted string""x";

可接受的语法:

s1 = R"(")";
s2 = R"("quoted string")";

是的,我同意括号引入了一些恼人的视觉效果。因此,我怀疑语法的作者是在考虑这种情况下很少需要额外的“ delim”,因为 )"不经常出现在字符串中。但是 OTOH,尾随/前导/孤立引号是相当常见的,所以例如你提出的语法(# 2)将需要一些 delim更频繁,这反过来又需要更频繁地将它从 R""..""改为 R"delim"..."delim"。希望你能明白。

语法能更好吗? 我个人更喜欢更简单的语法变体:

Rdelim"string contents"delim;

以上例子:

s1 = Rx"""x;
s2 = Rx""quoted string""x;

然而,为了正确工作(如果在当前语法中是可能的话) ,这种变体需要限制 delim部分的字符集,比如仅限于字母/数字(因为现有的操作符) ,还可能需要对初始字符进行一些进一步的限制,以避免与未来可能出现的语法冲突。
因此,我相信可以做出更好的选择,尽管在这种情况下没有什么 意义重大可以做得更好。