在字符串中使用反斜杠作为字面量而非转义字符的方法

12
bool stringMatch(const char *expr, const char *str) {   
    // do something to compare *(expr+i) == '\\'  
    // In this case it is comparing against a backslash
    // i is some integer
}

int main() {
    string a = "a\sb";
    string b = "a b";
    cout << stringMatch(a.c_str(), b.c_str()) << endl;
    return 1;
}

目前的问题是:Xcode在调试stringMatch函数时,并没有读入'\',因此expr似乎只是字面上的'asb'而不是'a\sb'。

Xcode会在这一行输出警告信息: string a = "a\sb" : 未知的转义序列

编辑:我已经尝试使用"a\\sb",但它被当成了字面上的"a\\sb"。


3
你的另一个选择是使用原始字符串字面量,但除非你正在编写正则表达式或类似内容,否则这有点过度了。这里是需要翻译的内容链接:http://en.cppreference.com/w/cpp/language/escape。 - chris
1
"a\sb" 应该可以正常工作。请在下面发表您所观察到的问题的详细信息。 - bames53
2个回答

23
bool stringMatch(const char *expr, const char *str) {   
   // do something to compare *(expr+i) == '\\'  
   // In this case it is comparing against a backslash
   // i is some integer
}

int main() {
    string a = "a\\sb";
    string b = "a b";
    cout << stringMatch(a.c_str(), b.c_str()) << endl;
    return 1;
}

C和C++默认将反斜杠视为转义字符。你需要在字符串中加入额外的反斜杠来告诉C不要将你的反斜杠视为转义字符。

下面是常见的转义字符:

  • \a - 响铃(蜂鸣)
  • \b - 退格
  • \f - 换页
  • \n - 换行
  • \r - 回车
  • \t - 水平制表符
  • \\ - 反斜杠
  • \' - 单引号
  • \" - 双引号
  • \ooo - 八进制表示
  • \xdd - 十六进制表示

编辑提示:在你的机器上,Xcode的行为异常。因此,我可以向你提供以下建议。

bool stringMatch(const char *expr, const char *str) {   
   // do something to compare *(expr+i) == '\\'  
   // In this case it is comparing against a backslash
   // i is some integer
}

int main() {
    string a = "a" "\x5C" "sb";
    string b = "a b";
    cout << stringMatch(a.c_str(), b.c_str()) << endl;
    return 1;
}

不用担心在声明string a时的空格,Xcode会将以空格分隔的字符串连接起来。
编辑2:实际上,Xcode会直接读取你的"a\\b",这是它处理转义反斜杠的方式。当你将string a = "a\\sb"输出到控制台时,你会看到a\sb。但是当你将string a作为参数或私有成员在方法之间传递时,它会将额外的反斜杠解释为字面量。你需要设计你的代码来考虑这一点,使其忽略多余的反斜杠。你可以自行决定如何处理字符串。
编辑3:编辑1是你最佳的答案,但这里还有另一个方法。
在你的stringMatch()方法中添加代码,将双反斜杠替换为单反斜杠。
你只需要在函数的开头添加这一行即可。
expr=[expr stringByReplacingOccurrencesOfString:@"\\\\" withString:@"\\"];

这应该可以解决双反斜杠的问题。

编辑4: 有些人认为编辑3是ObjectiveC,因此不够优化,所以还有一种在ObjectiveC++中的选择。

void searchAndReplace(std::string& value, std::string const& search,std::string const& replace)
{
    std::string::size_type  next;

    for(next = value.find(search);        // Try and find the first match
        next != std::string::npos;        // next is npos if nothing was found
        next = value.find(search,next)    // search for the next match starting after
                                          // the last match that was found.
       )
    {
        // Inside the loop. So we found a match.
        value.replace(next,search.length(),replace);   // Do the replacement.
        next += replace.length();                      // Move to just after the replace
                                                       // This is the point were we start
                                                       // the next search from. 
    }
}
编辑5: 如果你将stringMatch()中的const char *改为string`,它会更简单易懂。
expr.replace(/*size_t*/ pos1, /*size_t*/ n1, /*const string&*/ str );

第6版编辑:从C++11开始,存在类似原始字符串字面值的东西。 这意味着您不必转义,而可以编写以下内容:

string a = R"raw(a\sb)raw";

请注意,字符串中的raw可以被您选择的任何分隔符替换。这适用于实际字符串中想要使用子字符串(例如)raw)的情况。主要在需要经常转义字符时才使用这些原始字符串字面量,例如与std::regex结合使用。
顺便说一句,您现在拥有所有答案,所以您可以自己选择哪个实现方式可以给您带来最好的结果。

1
这里不需要使用字符串字面量拼接; "a\x5Csb" 就可以了。另外,关于 EDIT2,你在哪里看到了额外的反斜杠?是在调试器中吗?因为我相信 Xcode 调试器会显示转义后的字符串。所以包含单个反斜杠的正确字符串应该在调试器中显示两个反斜杠。无论你将字符串初始化为 "a\sb" 还是 "a\x5csb",都是如此。将其打印到控制台上以查看实际内容。 - bames53
1
我认为你的测试用例肯定有问题。在控制台打印不会从字符串中删除额外的反斜杠。如果一个反斜杠没有出现在打印到控制台的字符串中,那么它就不在这个字符串中。string a = "a\\sb"; assert(a[0] == 'a'); assert(a[1] == '\\'); assert(a[2] == 's'); - bames53
"a" "\\" "sb""a\\sb" 产生相同的字符串。 "\" 会导致编译器警告 missing terminating '"' character"\\""\x5C" 再次产生相同的字符串。 - bames53
我同意Derpy Derp所说的,当你将"a\b"传递到控制台显示时,我看到的是a\b;但是当我将其传递到函数中时,它仍然是a\b,但有什么解决方法吗? - monkeyMoo
我没有使用Photoshop,但是我使用了我的图像优化引擎将其重新调整为小尺寸。正如您所看到的,这是未经优化的图像,并且使用Photoshop重新调整为小尺寸:[截图](https://dl.dropbox.com/u/90690956/Screen%20Shot%202012-09-24%20at%2001.15.53-AM_2.png)@bames53 - Derpy Derp
显示剩余30条评论

9
Xcode报出此警告是因为它将"a\sb"中的\s解释为一个转义序列,但\s并不是有效的转义序列。它被替换为s,所以该字符串变成了"asb"。
"a\\sb"这样转义反斜杠是正确的解决方案。如果您尝试了这种方法仍然无法解决问题,请提供更多细节。
以下是示例:
#include <iostream>
#include <string>

int main() {
    std::string a = "a\\sb";
    std::cout << a.size() << ' ' << a << '\n';
}

这个程序的输出如下所示:

4 a\sb

如果你得到了不同的输出,请发帖说明。同时,请准确地描述你之前尝试“a\\sb”时遇到的问题。
在C++中,正则表达式可能会很麻烦,因为必须以这种方式转义反斜杠。C++11具有原始字符串,不允许任何转义,因此转义反斜杠是不必要的:R"(a\sb)"

我已经尝试使用"a\sb",但它被读取为字面值"a\sb"。 - monkeyMoo
1
请仔细检查,并尝试运行我添加的示例程序。如果输出结果与预期不同,请发布反馈。 - bames53
你在 Xcode 中运行了代码吗,@bames53?我运行了,但是它正常运行。 - Derpy Derp
@DerpyDerp 不是在Xcode中,但我知道Xcode会正确地处理这段代码。 - bames53
Xcode 对于转义反斜杠的处理方式与其他工具不同。请查看我的编辑 @bames53。 - Derpy Derp
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接