Guava 是否提供了对字符串进行转义的方法?

Does Guava provide a method to unescape a String?

我需要转义 String.

中的特殊字符

Guava 提供了 Escaper class,它正是这样做的:

Escaper escaper = Escapers.builder()
        .addEscape('[', "\[")
        .addEscape(']', "\]")
        .build();

String escapedStr = escaper.escape("This is a [test]");

System.out.println(escapedStr);
// -> prints "This is a \[test\]"

现在我有一个转义的 String,我需要取消转义它,但我在 Guava 中找不到任何东西可以做到这一点。

我期待 Escaper 有一个 unescape() 方法,但事实并非如此。

编辑:我知道取消转义可能很棘手,甚至在某些无意义的情况下是不可能的。

例如,这种 Escaper 用法可能会导致歧义:

Escaper escaper = Escapers.builder()
        .addEscape('@', " at ")
        .addEscape('.', " dot ")
        .build();

除非转义数据仅包含电子邮件地址,否则您无法通过取消转义来安全地取回您的数据。

安全使用 Escaper 的一个很好的例子是 HTML 个实体:

Escaper escaper = Escapers.builder()
        .addEscape('&', "&")
        .addEscape('<', "&lt;")
        .addEscape('>', "&gt;")
        .build();

在这里,您可以安全地转义任何文本,将其合并到 HTML 页面中,并随时 取消转义 以显示它,因为您涵盖了所有可能的歧义.

总而言之,我不明白为什么转义如此有争议。我认为开发人员有责任正确使用此 class,了解他的数据并避免歧义。 根据定义,转义意味着您最终将需要转义。否则就是混淆或其他概念。

不,不是。显然,这是故意的。引用 this discussion Chris Povirk 的回答:

The use case for unescaping is less clear to me. It's generally not possible to even identify the escaped source text without a parser that understands the language. For example, if I have the following input:

String s = "foo\n\"bar\"\n\";

Then my parser has to already understand \n, \", and \ in order to identify that...

foo\n\"bar\"\n\

...is the text to be "unescaped." In other words, it has to do the unescaping already. The situation is similar with HTML and other formats: We don't need an unescaper so much as we need a parser.

看来你得自己动手了。

如果您只需要转义 HTML 实体、Unicode 字符和控制字符,例如 \n\t,您可以简单地使用 StringEscapeUtils class from Apache Commons Lang.

万一有人需要单个字符转义器,下面是一个非常简单的实现:

@Nonnull
public String unescape(@Nonnull String text) {
    CharacterIterator i = new StringCharacterIterator(text);
    StringBuilder result = new StringBuilder(text.length());
    for (char c = i.first(); c != DONE; c = i.next()) {
        if (c == escaped) {
            result.append(i.next());
        } else {
            result.append(c);
        }
    }
    return result.toString();
}