请教java自带的正则表达式问题

[size=large]需要匹配的字符串是:[/size]
##$a7a-5064-2460-6$b精装$dCNY26.00$z7-313-1037-0

[size=large]具体要求是:[/size]
1、前两位是两个##、两个数字或者一个#,一个数字。
2、后面的每组字符串都是以$符号开头,$后面是字符、数字下划线、汉字组成的字符串。
3、$a、$b、$d的字符串不可重复,出现次数是0或1次;
$z可重复,出现次数不做限制。
4、$a、$b、$d没有顺序限制。

[size=large] 我写出的正则表达式:[/size]
(^[#0-9]{2})([$a]{2}[\w\d-]+)?([$b]{2}[color=blue].*[/color])?([$d]{2}.*)?([$z]{2}[\w\d-]+)?

[size=large]匹配中出现的问题:[/size]
     1、由于上述表达式中蓝色字体的.*能够匹配任意字符,所以如果不写对$d、$z字符串的正则表达式\([$d]{2}.*\)?\([$z]{2}[\\w\\d-]+\)? 也能够匹配到$d、$z的字符串。
     2、正则表达式匹配的时候是按照顺序来匹配的。也就是说在正则表达式中$a在$b的前面,如果匹配字符串中没有$a字符串组或者$a字符串组在$b、$d的后面的话,就不能够匹配成功了。针对这个问题我想到的办法是用正则表达式中的“或  |”来组合条件,但是考虑到匹配字符串中以$开头的字符串组比较多,感觉行不通。

 [size=large]实现中遇到的难点:[/size]
     1、针对由于.*能够匹配任意字符,造成正则表达式中从$d开始,如果不写的话也能够匹配的“$d”和“$z”字符串。应该如何界定$b的结束,从而可以判断出下一组$开头的字符串的开始?
    2、如何能够不限定“$a、$b、$d、$z”这些字符串组的顺序,只判断是否在字符串中出现及出现次数?
     3、java自带的正则表达式中除了“.”可以匹配汉字之外,还有什么方法能够匹配汉字?

[b][color=red][size=medium] 急用,请各位指点。[/size][/color][/b]

[b]问题补充:[/b]
首先谢谢 congjl2002 (高级程序员) 对我提出问题的解答。对于您的疑问 我在将我的问题补充一下。

首先说明一下上述需要匹配的字符串:
上述字符串对应一个字段号码,每个字段号码对应的字段内容是由多个子字段组成(子字段即:$a7a-5064-2460-6 或者 $dCNY26.00)。$a、$b是子字段标识符。
1、每条字段内容中,子字段标识符(即$a、$b)不定,$a开始到下个$结束是子字段$a对应的子字段内容。具体每条字段中的子字段标识符有哪些,需求中已提供。
2、$后面的内容字母、数字、下划线、“-”、“.”和汉字都有可能出现。例如下面的字段内容中:
1#$20030113d2003####em#y0实用客户英语$b专著$dD634.31-61$9zhao qing tian$f(清)何道生撰$z199?-2001
[b]问题补充:[/b]
我现在想用正则表达式是想两种功能:
1、正向验证。即页面中输入需要匹配的子字段内容后,使用正则表达式验证是否正确。正确将各个子字段合成一个字段内容。
2、逆向解析。即拿到整条字段内容或者多条字段内容时,使用正则表达式验证是否正确。包括该字段中子字段的标识符(即$a $b $d $z)是否正确,及它们的重复性是否正确。
[b]问题补充:[/b]
congjl2002 (高级程序员) 你给我提供的正则表达式是用于javascript中的正则表达式对吧?验证没有问题
刚刚想到一个问题,由于javascript的正则表达式和java自带的正则表达式有些语法稍微有些区别,因此我们可能要写两套正则表达式。javascript中的正则表达式用于正向的验证,java自带的正则表达式用于逆向的解析。java自带的正则表达式逆向解析时主要是有大量数据,也就是多条字段内容时,验证其中一整条字段内容会方便一些。但是现在想一下感觉后台如果自己来写解析的方法,比用正则表达式解析会更方便。这个想法正在商讨中。
我现在还在尝试用java自带的正则表达式来解析字段内容。对于 实现中遇到的难点中的第3条 现在仍然是难点。如果正则表达式中用([$b]{2}.*)? .* 来匹配出现汉字的情况的话,当用([$b]{2}.*)? 来匹配整条字段内容的时候,会将$b开始直到最后所有的字符串都匹配上。不想javascript中可以用\w来匹配汉字 ,不至于把所有字符匹配上。
郁闷啊!!!!!!!
请问有什么方法能够在java自带的正则表达式中准确的匹配出汉字吗?
请指点迷津!
[b]问题补充:[/b]

congjl2002 (高级程序员)

之前没有弄清楚正则表达式在不同的语言之间是否有区别。造成这样的原因是,在开始学习的时候,将教程中的例子在RegexTester 工具中测试正确,放到类中间加上了转义字符结果有时也会有区别;再就是jdk API中提供的java.util.regex.Pattern类中对\w能够匹配字符的说明是   单词字符:[a-zA-Z_0-9]  和你推荐的那篇文章中的说明有所出入(这几天学习正则表达式看的资料就是你提供的那篇文章)。文章中\w 能够匹配的字符是  字母或数字或下划线或汉字    。所以感觉他们之间是有所不同的。

[b]问题补充:[/b]
congjl2002 (高级程序员) 你好

你给我提供的正则表达式 我试过了,在RegexTester工具中测试是好的。但是在java中验证不通过。下面是我写的程序。方便的话测试一下。

public static void main(String[] args) {
String regex = "(^[#0-9]{2})([$a]{2}[\w\d-]+(?!$)?)+([$b]{2}(.?){10}(?!$)?)?([$d]{2}[\w.]*(?!$)?)?([$z]{2}[\w\d-]+(?!$)?)?$";
String matcher = "##$a7a-5064-2460-6$b精装$dCNY26.00$z7-313-1037-0";
find(regex,matcher);

}

/**
 * find 方法扫描输入序列以查找与该模式匹配的下一个子序列。
 * 
 * 通过m.find()方法,是按照指定模式与整条字符串进行匹配的 m.groupCount()可以获取指定模式中的分组数 m.group() ==
 * m.group(0) 即匹配成功的整条字符串
 * 
 * @param p
 * @param m
 */
public static List<String> find(String regex, String matcher) {
    List<String> list = new ArrayList<String>();
    Pattern p = Pattern.compile(regex);// Pattern(模式类);Pattern类是用来表达和陈述所要搜索模式的对象
    Matcher m = p.matcher(matcher);
    boolean finded = m.find();
    StringBuffer sb = new StringBuffer(); // 该对象用于存储匹配出的字符串,用于下面判断匹配出的内容是否是子字段(即是否包含$)

    while (finded) {
        for (int i = 0; i <= m.groupCount(); i++) {
            // 匹配出的第一个结果是整个字符串
            if (i == 0)
                continue;
            sb.append(m.group(i));
            // 匹配出的是指示符 ## 或者 #数字 或者 数字#
            if (i == 1 && m.group(i) != null){
                list.add(m.group(i));
                continue;
            }
            // 判断匹配出的字符串是否是子字段内容,即是否包含$
            if (i != 0 && sb.toString().indexOf("$") == -1)
                continue;
            sb.delete(0, sb.toString().length());

            if(m.group(i) == null) continue;
            list.add(m.group(i));
        }
        finded = m.find();
    }

    for (int i = 0; i < list.size(); i++) {
        System.out.println(i + " " + list.get(i));
    }
    return list;
}

如果把String regex = "^[\#0-9]{2}(\$[abdz][\w-.]*(?!$)?)+$";

运行程序匹配不出任何东西了。帮忙看看!

4个回答

[color=red]String regex = "^[\#0-9]{2}(\$[abdz][\w-.]*(?!$)?)+$"; [/color]这个确实应该匹配不出东西,因为你要的是判断整个字符串是否符合规定,并不是要查找,匹配出每个$a这样的组合,所以那个做的就是判断整个字符串是否符合,只要有一组不符合,就什么都查不出来,你值保留[color=red]##$a7a-5064-2460-6[/color]是可以查出来的,因为后面你的代码里还有其他字符,如果jdk里是匹配字母的话,那就把[color=red]\w[/color]改成[color=red][\p{InCJK Unified Ideographs}&&\P{Cn}][/color]吧
参考一下这个帖子
[url]http://topic.csdn.net/u/20080629/00/2f669f44-6e30-4e2e-9cce-08889dba2ae2.html[/url]

[code="java"]^(##|\d\d|#\d)(\$[abdz][\w-.]*(?!$)?)*[/code]
只想出一个匹配这个字符串的,但是$a,$b等的数量限制起来比较困难,没想好怎么用正则表达式,你最好用string的indexof来检查
另外你的要求中的[color=red]2、后面的每组字符串都是以$符号开头,$后面是字符、数字下划线、汉字组成的字符串。[/color]是不是有问题啊,你字符串里显然还有“-”和“.”

[code="java"]^[#0-9]{2}(\$[abdz][\w-.]*(?!$)?)+$[/code]
这个除了次数,用该符合你的要求了,次数的判断要在一个正则里写真的很难,而且你的项数还是不固定的,你看看是不是换个方法,另外为什么非要用一个正则判断呢?
还是建议要么拆开判断,要么将次数判断放到外面

正则表达式是固定的,在什么语言都是一样,只是java里可能要用“\”来转义一些字符,但整体不会变
像你这样写[color=red]([$b]{2}.*)? [/color],是以“$”或“b”开头的,要是有“b$"这样的就会有问题,我写的中间有一个[color=red]-.](?!$)?[/color],意思是匹配到“$”符号之前,因此,如果是“$a图书$b图书"也可以匹配出“$a图书",不会一直到最后,另外,你用“\w"为什么不行呢?他匹配的只是“匹配字母或数字或下划线或汉字”,要比“.*范围小的多

建议见看一下这篇文章
[url]http://congjl2002.iteye.com/blog/154604[/url]

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问