在字符类中转义单个字符

4

如何在Java中逐个转义正则表达式元字符?

我正在为一个Android应用程序工作,处理包含许多正则表达式认为具有特殊含义的字符的文件,包括\?.()[*\^+'-。我将读取两个文件:

  1. 单词字典列表,每个单词占一行。
  2. 可以用于过滤单词字典列表中单词的字符列表。

以下是每个的示例。

字典:

 /it*
 t1*]
 ?\<t
 item

(是的,这些都是单词。前三个是缩写的盲文ASCII表示法,分别代表“针脚”,“老师”和“思考”。现在你知道了。)

要使用的“字母”:

?]*/\<1eitm

我希望将这些字母包含在一个类似于这样的正则表达式中:

String letters = "?]*/\<1eitm";
Pattern pattern = Pattern.compile("^["+letters+"]{4}$", Pattern.MULTILINE);

我的目标是从字典列表中选择所有只包含给定字符且长度为指定长度的单词。我无法控制请求字符在文件中出现的顺序。
如果我只使用非元字符,如<1eitm>,那么这个问题可以很好地解决。不知何故,我需要转义元字符,并确保字符,如]和-出现在方括号内的正确位置。
我可以手动完成这个过程,但希望有一个内置的命令来替代我完成这个任务。到目前为止,我找到的所有命令中只有Pattern.quote()命令不能给我想要的结果。
以下是我可能需要在方括号内使用的所有字符列表:
\_-,;:!?.'"()[]@*/\&#%^+<=>~$0123456789abcdefghijklmnopqrstuvwxyz

以下是我在Android测试中使用的基本代码:

package com.example.quote;

import android.app.Activity;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.util.Log;

import java.io.IOException;
import java.io.InputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        AssetManager am = this.getAssets();
        try {
            String dictionary = readFile(am, "dictionary.txt");
            String regex = readFile(am, "regex.txt");

            regex = "^["+regex+"]{4}$"; // THIS IS WHERE I NEED TO MAKE A CHANGE

            Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
            Matcher matcher = pattern.matcher(dictionary);

            while (matcher.find()) {
                Log.d("TEST", matcher.group(0));
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private String readFile(AssetManager am, String fileName) throws IOException {
        InputStream is = am.open(fileName);

        int size = is.available();
        byte[] buffer = new byte[size];
        is.read(buffer);
        is.close();

        String string = new String(buffer, "UTF-8");

        return string;
    }
}

相关且可能有帮助的链接:https://dev59.com/HWgv5IYBdhLWcg3wW_h_ - J0e3gan
2个回答

2
使用Pattern.quote()函数引用所有特殊字符并将它们匹配为字符字面量。该函数通常通过使用引号\Q...\E结构来包围提供的字符串来实现。
在Oracle/OpenJDK(参考)实现中,使用\Q...\E结构来包围字符串,引用的结构从Java 6中可以在字符类内被识别,因此返回值可以在字符类内使用。
Android使用ICU实现,根据文档描述,也允许在字符类内工作\Q\E。因此,无论Pattern.quote()函数在ICU中如何工作(添加转义\或使用引用\Q...\E结构),在这方面它应该与参考实现(Java 6)类似。
regex = "^[" + Pattern.quote(regex) + "]{4}$";

经过一些实验,我发现 regex = "^["+Pattern.quote(regex)+"]{4}$"; 对我来说很有效。谢谢。 - James Newton

0

为Java正则表达式转义特殊字符有些麻烦,但不难。原因是反斜杠字符\在Java字符串中是一个转义字符,因此字面字符串"\ "是反斜杠。但单个反斜杠也是正则表达式中的转义字符,因此在Java正则表达式模式匹配字符串中,特殊字符应该使用双反斜杠进行“转义”! 因此,为了匹配问号字符?,您的正则表达式必须包括\\?。 为了匹配单个反斜杠,您的正则表达式必须包括\\\\

让我们以您的String为例:

String letters = "?]*/\<1eitm";

这里的前五个字符应该被转义 - 也就是说,要加上双反斜杠转义序列\\

String letters = "\\?\\]\\*\\/\\\\<1eitm";

如上所述,反斜杠本身必须以转义序列为前缀,然后再加倍。

希望这有所帮助。


我明白你没有说出来的意思,也就是说没有内置命令可以自动执行所有这些转义。是这样吗?换句话说,我必须手动检查输入字符串并在找到任何元字符之前添加 \\\\\ - James Newton
当我在这里进行测试时,我发现有效的Java字符串表达式是这个:"(?m)^[]?*/\\\\<1eitm]{4}$"。换句话说,只有\字符需要三次转义,并且]字符需要放在开头。 - James Newton
是的,非常抱歉,那是因为它们在方括号 [] 中作为字符类的边界。我漏掉了这一点。 - David Faber

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