【问题标题】:Replace everything with spaces except line terminators用空格替换除行终止符之外的所有内容
【发布时间】:2014-10-03 10:05:11
【问题描述】:

以下替换是否保证使行终止符\r\n 完好无损?

"Hello\r\nWorld".replaceAll(".", " ")

我不确定是否可以为所有正则表达式全局指定 DOTALL 标志。

这样写会不会更安全?

"Hello\r\nWorld".replaceAll("[^\r\n]", " ")

【问题讨论】:

  • 您希望 DOTALL off 适合您的情况。默认情况下它是关闭的。无论如何,使用 Java 尝试一次就足够了,你得到的几乎就是你保证得到的。
  • "Hello\r\nWorld".replaceAll(".", " ") 会将\r\n 留在原始输入中。
  • @MarkoTopolnik 所以没有办法在特定的正则表达式之外全局启用DOTALL?
  • 从技术上讲,您可以在开头使用(?s) 为整个表达式启用它,但是没有为从那时起创建的所有正则表达式设置全局选项这样的事情。
  • 是的,Regex API 没有全局配置——当然,这是一件非常好的事情。

标签: java regex newline


【解决方案1】:

. 和行分隔符

由于. 将\r 和\n 视为行分隔符(\r、\n、\r\n1、\u0085、\u2028、@987654331 @),行分隔符序列\r\n或任何涉及\r或\n的序列自然不会被.匹配。

1 关于\r\n行终止符序列,当涉及$时观察到更有趣的行为,因为引擎在回溯时需要将\r\n视为原子行分隔符.

为内联正则表达式设置标志

您可以指定任何标志(CANON_EQ2 除外)以启用整个正则表达式,甚至是正则表达式的一部分,(?<flags>) 用于前一种情况,而(?<flags>:<re>) 用于后一种情况。这在Pattern 类文档的Special constructs 部分中进行了描述。

可用的标志是i (CASE_INSENSITIVE), d (UNIX_LINES), m (MULTILINE), s (DOTALL), @9876543551@ (@987654 )、x (COMMENTS)、U (UNICODE_CHARACTER_CLASS,来自 Java 7)。

可以在所有要关闭的标志之前添加一个 - 前缀来关闭标志,如文档 (?idmsuxU-idmsuxU) 和 (?idmsux-idmsux:X) 中的示例所示。

2 Oracle 实现的源代码显示c 是CANON_EQ 的标志,但它完全没用,因为CANON_EQ 在正则之前被检查和处理表达式被正确解析(在我看来这是一件坏事,而且它显然搞砸了以至于无法使用)。

为所有正则表达式设置标志

如果您要查找的是一个全局选项,用于指定设置该选项后编译的所有正则表达式将默认设置某些标志,那么答案是否,没有可用的。

【讨论】:

    【解决方案2】:

    如the Pattern Javadocs中所述:

    正则表达式. 匹配除行终止符之外的任何字符除非指定了DOTALL 标志。

    因此,如果您只使用第一个表达式,它将按您的意愿工作:

    "Hello\r\nWorld".replaceAll(".", " ")
    

    【讨论】:

    • 所以没有办法在特定的正则表达式之外全局启用DOTALL?
    • @FredOverflow 只能在创建每个Pattern 对象时指定标志。
    【解决方案3】:

    如果您查看 String.replaceAll() 的实现,它会在内部使用 Pattern,没有 DOTALL 标志,没有参考任何全局设置。

    public String replaceAll(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceAll(replacement);
    }
    

    Pattern.compile(regex) 将 0(无标志)传递给 Pattern.compile(regex, flags),这将禁用 DOTALL 模式。

    public static Pattern compile(String regex) {
        return new Pattern(regex, 0);
    }
    

    Pattern 可用于手动添加 DOTALL 标志,但默认不使用它,这会改变 Pattern 的单个实例的行为方式

    一个成功的例子:

    String test = "Hello\r\nWorld";
    
    System.out.println(String.format("With DOTALL >%s<",
            Pattern.compile(".", Pattern.DOTALL).matcher(test).replaceAll(" ")));
    
    System.out.println(String.format("Without DOTALL >%s<", 
            Pattern.compile(".").matcher(test).replaceAll(" ")));
    

    输出

    With DOTALL >            <
    Without DOTALL >     
         <
    

    【讨论】:

    • OP其实不需要DOTALL,就是怕其他代码的一些设置会出现。
    • 顺便说一句,您可以设置 DOTALL,而无需在行首显式使用带有“(?s)”标志的Pattern。
    • @DmitryGinzburg 这正是我担心的!
    • 在您的特定正则表达式的开头添加“(?s)”当然不是“全局”设置,这不是您的应用程序的其他部分可能意外做的事情...
    猜你喜欢
    • 2019-03-23
    • 1970-01-01
    • 2013-12-26
    • 2014-11-20
    • 2011-08-27
    • 2018-05-12
    • 1970-01-01
    • 2021-11-27
    • 1970-01-01
    相关资源
    最近更新 更多