java - 使用 String.replaceFirst(regexp, "$1") 获取匹配的子字符串时得到空字符串,正则表达式有什么问题?

标签 java regex

我要转换ANSI Escape序列为IRC color序列。

所以我写了一个正则表达式 1 \e\[([\d;]+)?m,但是 shell_output_string.replaceFirst ("\\e\\[([\\d;]+)?m", "$1") 将返回匹配的子字符串和其余不匹配的子字符串。

然后我写了正则表达式2 .*\e\[([\d;]+)?m.*,希望它能匹配整个字符串,并用匹配的子字符串替换它,但是,replaceFirst (".*\\e\\[([\\d;]+)?m.*", "$1") 返回空字符串,但匹配 (".*\\e\\[([\\d;]+)?m.*")true。这个正则表达式有什么问题?

以下问题与此问题非常相似:Pattern/Matcher group() to obtain substring in Java?

示例代码

import java.util.regex.*;
public class AnsiEscapeToIrcEscape
{
    public static void main (String[] args)
    {
//# grep --color=always bot /etc/passwd
//
//bot:x:1000:1000:bot:/home/bot:/bin/bash
byte[] shell_output_array = {
0x1B, 0x5B, 0x30, 0x31, 0x3B, 0x33, 0x31, 0x6D, 0x1B, 0x5B, 0x4B, // ^[[01;31m^[[K  (#1 - #11)
0x62, 0x6F, 0x74,   // bot  (#12 - #14)
0x1B, 0x5B, 0x6D, 0x1B, 0x5B, 0x4B, // ^[[m^[[K (#15 - #20)
0x3A, 0x78, 0x3A, 0x31, 0x30, 0x30, 0x30, 0x3A, 0x31, 0x30, 0x30, 0x30, 0x3A,   // :x:1000:1000:    (#21 - #33)
0x1B, 0x5B, 0x30, 0x31, 0x3B, 0x33, 0x31, 0x6D, 0x1B, 0x5B, 0x4B, // ^[[01;31m^[[K  (#34 - #44)
0x62, 0x6F, 0x74,   // bot  (#45 - #47)
0x1B, 0x5B, 0x6D, 0x1B, 0x5B, 0x4B, // ^[[m^[[K (#48 - #53)
0x3A, 0x2F, 0x68, 0x6F, 0x6D, 0x65, 0x2F,   // :/home/  (#54 - #60)
0x1B, 0x5B, 0x30, 0x31, 0x3B, 0x33, 0x31, 0x6D, 0x1B, 0x5B, 0x4B, // ^[[01;31m^[[K  (#61 - #71)
0x62, 0x6F, 0x74,   // bot  (#72 - #74)
0x1B, 0x5B, 0x6D, 0x1B, 0x5B, 0x4B, // ^[[m^[[K (#75 - #80)
0x3A, 0x2F, 0x62, 0x69, 0x6E, 0x2F, 0x62, 0x61, 0x73, 0x68, // :/bin/bash   (#81 - #90)
};
        String shell_output = new String (shell_output_array);
        System.out.println (shell_output);
        System.out.println ("total " + shell_output_array.length + " bytes");

        final String CSI_REGEXP = "\\e\\[";
        final String CSI_SGR_REGEXP_First = CSI_REGEXP + "([\\d;]+)?m";
        final String CSI_SGR_REGEXP = ".*" + CSI_SGR_REGEXP_First + ".*";

        System.out.println (shell_output.replaceFirst(CSI_SGR_REGEXP_First, "$1"));
        System.out.println (shell_output.replaceFirst(CSI_SGR_REGEXP, "$1"));
    }
}

最佳答案

正则表达式是贪婪的 - 也就是说,每个模式都会尝试匹配尽可能多的输入。

这意味着当模式以 .* 开头时,该模式的该部分将尝试覆盖尽可能多的输入文本 - 如此有效地迫使模式的其余部分尝试找到开始的匹配项从输入字符串的末尾开始向前移动。

那么,从字符串末尾开始的模式其余部分的第一个匹配是什么(或者,如果您愿意,最后一个匹配的子字符串是什么)?它位于输入的倒数第二行,仅包含 ^[m

之所以匹配,是因为模式的整个 ([\d;]+) 部分通过以下 ? 变得可选.

反过来,这意味着,由于最终表达式没有数字或 ;,因此 $1 组为空 - 因此您将得到空字符串输出。

至少,这是我在没有靠近 Java 机器进行测试的情况下所估计的。希望对您有所帮助。

关于java - 使用 String.replaceFirst(regexp, "$1") 获取匹配的子字符串时得到空字符串,正则表达式有什么问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19489212/

相关文章:

java - 如何使用选项检查标签是否已选中

java - Tomcat 找不到 Postgres 驱动程序

java - 具有两个 Android 应用程序模块的 Gradle 项目

regex - 最小长度的模式匹配?

java - 如何检查输入字符串是否包含空格?

java - 在泛型中使用继承的有问题的声明

jquery - 有效 css 和/或 jQuery 选择器的正则表达式

php - 如何获得带有中文的 preg_match 2 位点(可选)?

regex - 查找文件的正则表达式

java 移动数组中的元素