Java模式匹配器/匹配器

4
这是一段示例文本:\1f\1e\1d\020028。我无法修改输入文本,我正在从文件中读取长字符串。
我想要提取以下内容:\1f\1e\1d\02 为此,我编写了以下正则表达式模式:"\\[a-fA-F0-9]" 我正在使用PatternMatcher类,但我的匹配器无法使用上述正则表达式找到模式。我已在一些在线正则表达式网站上测试了这个正则表达式,并出奇地得到了结果。
我错在哪了?
原始代码:
public static void main(String[] args) {
    String inputText = "\1f\1e\1d\02002868BF03030000000000000000S023\1f\1e\1d\03\0d";
    inputText        = inputText.replace("\\", "\\\\");

    String regex     = "\\\\[a-fA-F0-9]{2}";

    Pattern p = Pattern.compile(regex);
    Matcher m = p.matcher(inputText);

    while (m.find()) {
        System.out.println(m.group());
    }
}

输出:没有任何东西被打印出来


1
我猜你的一些反斜杠正在转义你不想要的东西。但是,为了确保,你必须向我们展示你的实际代码。 - azurefrog
\\[a-fA-F0-9] 查找反斜杠后跟一个字母或数字。我认为你想查找反斜杠后跟两个字母或数字。我猜你可以想办法解决这个问题。 - ajb
1
你是否正确格式化了输入字符串?我认为它应该是 '\1f\1e\1d\020028'。 - kaos
1
为了方便帮助您,发布使用此正则表达式的代码示例。 - Pshemo
我无法在源代码中修改输入字符串。但是,一旦从文件中读取,就可以进行修改并添加额外的反斜杠。但是,我在这方面还没有成功。 - sudipn
1
这是您输入文件的文本吗?我们可以看一下您是如何读取它的吗?另外,当您打印所读内容时,您看到了什么? - Pshemo
4个回答

2

您需要正确阅读文件,并将 '\' 字符替换为 '\\\\'。假设在您的项目中有一个名为 test_file 的文件,其内容如下:

\1f\1e\1d\02002868BF03030000000000000000S023\1f\1e\1d\03\0d

以下是读取文件并提取值的代码:

public static void main(String[] args) throws IOException, URISyntaxException {        
    Test t = new Test();
    t.test();
}

public void test() throws IOException {        
    BufferedReader br =
        new BufferedReader(
            new InputStreamReader(
                getClass().getResourceAsStream("/test_file.txt"), "UTF-8"));
    String inputText;

    while ((inputText = br.readLine()) != null) {
        inputText = inputText.replace("\\", "\\\\");

        Pattern pattern = Pattern.compile("\\\\[a-fA-F0-9]{2}");
        Matcher match = pattern.matcher(inputText);

        while (match.find()) {
            System.out.println(match.group());
        }
    }
}

你的代码确实可以工作。但是,当我做了类似于你上面看到的东西时,它却不能工作。 - sudipn
问题在于转义输入字符串。请查看更新。我使用了来自Apache Commons Lang的StringEscapeUtils。 - kaos
@bullzeye 解释了 escapeJava 方法将返回 Unicode 表示而不是八进制表示,因此你会得到 \u0001\u0000 而不是 \1\0。这就是为什么需要使用 replace("\\u000", "\\") 方法(将 \u0001 转换为像你字符串中的 \1)。 - Pshemo
@bullzeye 无论如何,这种方法在\03的情况下都会失败,因为它依赖于一个假设,即您只会使用\x来表示八进制值,而不是\xx,后者可以表示大于15的值,需要用两个十六进制字符来编写,这将使转义返回\u00XX - Pshemo
@bullzeye 此方法也不会转义由\123(十进制为83 -> 'S'字符)表示的字符,因为它是Java语言中使用的普通字符,不需要转义。 - Pshemo
你需要搜索所有的\uXXXX,并将XXXX重新计算为八进制值(不大于\277,因为这是Java可以处理的最大值)。如果我们使用Integer.parseInt(strValue,radix)Integer.toString(intValue,radix),那实际上并不难。 - Pshemo

2
您的字符串
String inputText = "\1f\1e\1d\02002868BF03030000000000000000S023\1f\1e\1d\03\0d";

实际上不包含任何\文本,因为根据Java语言规范在第3.10.6.字符和字符串文字的转义序列节中,\xxx将被解释为Unicode表中索引为八进制(基数/底数为8)值由xxx部分表示的字符。
例如:\123 = 1*82 + 2*81 + 3*80 = 1*64 + 2*8 + 3*1 = 64+16+3 = 83,表示字符S 如果您在问题中提供的字符串与您的文本文件中的字符串完全相同,则应将其编写为
String inputText = "\\1f\\1e\\1d\\02002868BF03030000000000000000S023\\1f\\1e\\1d\\03\\0d";

(带有转义的 \,现在它将代表字面意义。)
“older version of my answer” 的英译是:

没有看到您的代码,很难确定您具体做错了什么。由于您的正则表达式可以匹配一个 \ 和一个放在它后面的十六进制字符,所以您应该能够找到至少 \1\1\1\0

无论如何,以下是您可以找到问题中提到的结果的方法:

String text = "\\1f\\1e\\1d\\020028";
Pattern p = Pattern.compile("\\\\[a-fA-F0-9]{2}");
//                                          ^^^--we want to find two hexadecimal 
//                                               characters after \
Matcher m = p.matcher(text);
while (m.find())
    System.out.println(m.group());

输出:

\1f
\1e
\1d
\02

你提到的代码是可以工作的。但是,当我做了类似的事情,就像你在上面看到的那样,它却不起作用。 - sudipn

0
尝试在末尾添加一个点号,例如:
\\[a-fA-F0-9].

0
如果您不想修改输入字符串,可以尝试类似以下的代码:
static public void main(String[] argv) {

            String s = "\1f\1e\1d\020028";
            Pattern regex = Pattern.compile("[\\x00-\\x1f][0-9A-Fa-f]");
            Matcher match = regex.matcher(s);
            while (match.find()) {
                    char[] c = match.group().toCharArray();
                    System.out.println(String.format("\\%d%s",c[0]+0, c[1])) ;
            }
    }

是的,它不完美,但你可以理解。


谢谢!这个解决方案部分地可行。对于我修改的答案中提到的输入字符串,输出如下:'\1f \1e \1d \160 \1f \1e \1d \0d'。 - sudipn

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