Java 要从部分或驼峰大小写字符串匹配的正则表达式?

Java 要从部分或驼峰大小写字符串匹配的正则表达式?,java,regex,Java,Regex,我想要一个正则表达式来匹配给定的部分或大小写字符串。例如,如果搜索集包含字符串“MyPossibleResultString”,我希望能够将其与以下类似项匹配: MyPossibleResultString MPRS MPRString 桃金娘 M 我还希望包括通配符匹配,例如: MyP*RString *PosResString 我的*字符串 如果不清楚我的意思,我能想到的唯一例子就是Eclipse的“开放式”对话框,这正是我要寻找的行为。我不太熟悉正则表达式的使用,所以我不确定在Ja

我想要一个正则表达式来匹配给定的部分或大小写字符串。例如,如果搜索集包含字符串“MyPossibleResultString”,我希望能够将其与以下类似项匹配:

  • MyPossibleResultString
  • MPRS
  • MPRString
  • 桃金娘
  • M
我还希望包括通配符匹配,例如:

  • MyP*RString
  • *PosResString
  • 我的*字符串

如果不清楚我的意思,我能想到的唯一例子就是Eclipse的“开放式”对话框,这正是我要寻找的行为。我不太熟悉正则表达式的使用,所以我不确定在Java中寻找解决方案是否重要。

单用一个正则表达式是不可能做到这一点的。您必须基于输入构建一个正则表达式,并使用它进行搜索。很容易看出,您不能使用单个正则表达式-用户可以搜索任何(cammel cased)字符串,因此您的正则表达式需要匹配任何(cammel cased)字符串,但它不再是搜索了。

正如danbruc所说,您必须为每个新查询生成一个新正则表达式。这段代码应该满足您的要求

public Pattern queryToPattern(String query) {
    StringBuilder sb = new StringBuilder();
    char[] chars = query.toCharArray();
    boolean incamel = false;
    for (int i=0; i < chars.length; i++) {
        if (chars[i] == '*') {
                            if (!incamel)
                    sb.append(".*");
        } else if (Character.isUpperCase(chars[i])) {
            if (incamel) {
                sb.append(".*");
            }
            sb.append(chars[i]);
            incamel = true;
        } else {
            sb.append(chars[i]);
        }

    }
    sb.append(".*");
    return Pattern.compile(sb.toString());
}
公共模式查询模式(字符串查询){
StringBuilder sb=新的StringBuilder();
char[]chars=query.toCharArray();
布尔incamel=false;
for(int i=0;i
对:MyP*RString的查询


创建一个模式:My.*p.*R.*String.*

Ok,因此如果您已经可以支持第一个示例中描述的匹配,我真的不明白为什么需要通配符功能。这就是我所说的。给定查询字符串查询,可以使用正则表达式创建正则表达式:

String re = "\\b(" + query.replaceAll("([A-Z][^A-Z]*)", "$1[^A-Z]*") + ".*?)\\b";
例如,查询
MyPosResStr
将成为正则表达式:

\\b(My[^A-Z]*Pos[^A-Z]*Res[^A-Z]*Str[^A-Z]*.*?)\\b
然后使用
Matcher.find
方法使用此正则表达式进行匹配,得到如下结果:

public static String matchCamelCase(String query, String str) {
    query = query.replaceAll("\\*", ".*?");
    String re = "\\b(" + query.replaceAll("([A-Z][^A-Z]*)", "$1[^A-Z]*") + ".*?)\\b";

    System.out.println(re);
    Pattern regex = Pattern.compile(re);

    Matcher m = regex.matcher(str);

    if  (m.find()) {
        return m.group();
    } else return null;
}
这将返回字符串str中第一个匹配的驼峰大小写查询


编辑:我添加了一行代码来处理通配符,因为在我疲惫不堪的昏迷中,我没有意识到需要通配符

您可以尝试以下方法:

class RegexTransformer {
    public String fromQuery(String query) {
        StringBuilder sb = new StringBuilder();
        sb.append("^");
        sb.append(query.replaceAll("(\\p{Upper}(?!\\p{Lower}))",
                "$1\\\\p{Alpha}*?"));
        sb.append("$");
        return sb.toString();
    }
}
请参阅,以获取有关消极先行断言
(?!pat)
、POSIX字符类
\p{class}
和不情愿量词
*?
的说明

示例测试用例:

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import org.junit.Test;

public class RegexTransformerTest {

    private RegexTransformer rt = new RegexTransformer();

    @Test
    public void testQueries() {
        String in = "MyPossibleResultString";
        String q1 = "MyPossibleResultString";
        String q2 = "MPRS";
        String q3 = "MPRString";
        String q4 = "MyPosResStr"; // this wont work
        String q5 = "M";

        test(in, q1, "^MyPossibleResultString$");
        test(in, q2, "^M\\p{Alpha}*?P\\p{Alpha}*?R\\p{Alpha}*?S\\p{Alpha}*?$");
        test(in, q3, "^M\\p{Alpha}*?P\\p{Alpha}*?R\\p{Alpha}*?String$");
        test(in, q5, "^M\\p{Alpha}*?$");
    }

    private void test(String in, String query, String expected) {
        assertEquals("transform", expected, rt.fromQuery(query));
        assertTrue("match", in.matches(rt.fromQuery(query)));
    }
}

Il Bhima的answear很棒,但我发现这段代码对我来说更好(请原谅我的C#,但它是一样的):

注意末尾的“*”允许使用不完整的“startof”短语(也允许不指定所有大写字母)
此外,“[^A-Z]*”匹配器后面的星号修复了工具箱答案中第四个问题,即小写字母在大写字母之后(它们应该直接出现在大写字母之后,而不是在下一个大写字母之前)。

如果Eclipse的行为与您所寻找的行为非常相似,那么,你能不能看看伊柯丽斯的源代码?我可以,当我继续寻找答案时,我会考虑这个选项:-你的意思是,例如,输入字符串“MyPosirS”将被解析来生成“MyPoSRS”的正则表达式,这可以匹配吗?是的,您必须根据用户输入生成一个正则表达式,并使用它进行搜索。您现在无法构建一个,因为您不知道输入,因此不知道正则表达式必须匹配什么。好的,这是有意义的。现在看起来很明显+1第一个示例不包括我希望“*PRS”匹配的情况,而“PRS”不应该匹配的情况。我想说的是,在编辑之前,它对一些模式不起作用,现在唯一不匹配的示例是没有显式悬空通配符的'M'/'MP'/'MPR'等。我相信这只是一个小因素,我确实喜欢它更简洁(我相信我很快就能读到它:-D)+1谢谢你抓住它!你说得对,那是我错过的另一个案子。接下来。如果目标字符串以小写“my”开头,regexp会是什么样子?i、 e.mPosResStr应该匹配。这是一种享受,目前为+1,但我会让时间成熟起来,看看另一个答案是否更好(在我无知的情况下,我目前无法真正判断这一点)。谢谢
pattern = Regex.Escape(pattern);
pattern = pattern.Replace(@"\*", ".*?");
pattern = Regex.Replace(pattern, "([A-Z][^A-Z]*)", "$1[^A-Z]*?") + ".*";