2011-10-22 100 views
14

我正在使用正則表達式來驗證字符串中的某種格式。這個字符串將成爲遊戲的一個規則。使用正則表達式檢查數字範圍

示例:根據規則,「DX 3」可以,但「DX 14」也可以,我也知道如何查看字符串並找到一個或多個「數字」,所以問題是該正則表達式也將匹配34,並且這個數字超出了規則的「範圍」...

我錯過了關於正則表達式的一些事情嗎?或者這是不可能的?

+0

您需要什麼範圍? – npinti

回答

29

不幸的是,有沒有簡單的方法來定義正則表達式的範圍。如果您是使用範圍1-23,你會擁有這樣的正則表達式:

([1-9]|1[0-9]|2[0-3]) 

說明:

  1. 要麼值爲1-9
  2. 或價值開始與圖1和隨後以0-9
  3. 或值以2開始,後面跟着具有0-3
+0

非常感謝!我正在嘗試,但我沒有使用「()」 – mrs1986

3

這並不是說短,不靈活。

例如,如果搜索1到19,則可以搜索「DX 1?[0-9]」,但是如果它不在數字邊界處結束,它很快就會變醜,規則不靈活。

將字符串分割爲空白,然後使用x> 0和x < 24更好理解並更靈活。

-1
package dev.dump; 

import java.text.MessageFormat; 
import java.util.ArrayList; 
import java.util.HashSet; 
import java.util.List; 
import java.util.Set; 
import java.util.Collections; 
import java.util.Locale; 
import java.util.regex.Matcher; 
import java.util.regex.Pattern; 

/** 
* Created by IntelliJ IDEA. User: User Date: 28.09.2007 Time: 9:46:47 To change this template use 
* File | Settings | File Templates. 
*/ 
class NumberDiapasone2RegExp { 
    private static final String invalidArgumentEmpty="Invalid argument \"{0}\" was found! {1}"; 
    private static final Pattern pattern=Pattern.compile("^(\\d+)-(\\d+)?$"); 
    private String src; 
    private String result=""; 
    private Long left; 
    private Long right; 
    private boolean transform09ToD; 

    public NumberDiapasone2RegExp(final String src) { 
    this(src, false); 
    } 

    public NumberDiapasone2RegExp(final String src, final boolean transform09ToD) { 
    this.transform09ToD=transform09ToD; 
    if (src==null || src.trim().length()==0) 
      throw new IllegalArgumentException(MessageFormat.format(invalidArgumentEmpty, 
                    src, 
                    "It cannot be empty.")); 
     if (src.indexOf("-")<0) 
      throw new IllegalArgumentException(MessageFormat.format(invalidArgumentEmpty, 
                    src, 
                    "It is supposed to have \"-\".")); 
     if (src.indexOf("-")!=src.lastIndexOf("-")) 
      throw new IllegalArgumentException(MessageFormat.format(invalidArgumentEmpty, 
                    src, 
                    "It is supposed to have only one \"-\".")); 
    Matcher syntaxChecker=pattern.matcher(src); 
    if (!syntaxChecker.find()){ 
     throw new IllegalArgumentException(MessageFormat.format(invalidArgumentEmpty, 
                   src, 
                   "It is supposed to be in format \"##-##\".")); 
    } 
    this.src=src; 
    parseAndCheck(); 
    String theSameDigits=""; 
    //the same digit goes towards result 
    if (left.toString().length()==right.toString().length()){ 
     for (int i=0; i<left.toString().length(); i++){ 
     if (i<right.toString().length() && 
      left.toString().charAt(i)==right.toString().charAt(i)){ 
      theSameDigits+=left.toString().charAt(i); 
     } 
     } 
     if (theSameDigits.length()>0){ 
     this.src=this.src.replaceFirst(Pattern.quote(theSameDigits),""); 
     this.src=this.src.replaceFirst(Pattern.quote("-"+theSameDigits),"-"); 
     parseAndCheck(); 
     } 
    } 
    result=glueParts(compact(transform09ToD, toParts()));  
    Matcher m=secondCompact.matcher(result); 
    while (m.find()){ 
     result=m.group(1).replace("(","").replace(")","")+"["+m.group(2).replaceAll("[\\[\\]]","")+m.group(3).replaceAll("[\\[\\]]","")+"][0-9]"; 
     m.reset(result); 
    } 
    //compact squares again 
    StringBuffer sb=new StringBuffer(); 
    Pattern squresP=Pattern.compile("(\\[(\\d|-)+\\])"); 
    m=squresP.matcher(result); 
    while (m.find()) { 
     m.appendReplacement(sb, Matcher.quoteReplacement(compactSquares(m.group(1)))); 
    } 
    m.appendTail(sb); 
    result=sb.toString(); 
    result=result.replaceAll("\\[(\\d)-\\1\\]","$1"); 
    result=result.replaceAll("\\[(\\d)\\]","$1"); 
    result=result.replace("{1}","").replace("{0,1}","?"); 
    if (result.indexOf("|")>=0) result=theSameDigits+"("+result+")"; 
    else result=theSameDigits+result; 
    if (result.startsWith("(") && result.endsWith(")")) result=result.substring(1, result.length()-1); 
    } 

    private static Pattern secondCompact=Pattern.compile("(.*)(\\[\\d-?\\d\\]|\\d)\\[0-9\\]\\|(\\[\\d-?\\d\\]|\\d)\\[0-9\\]"); 

    static List<String> compact(boolean transform09ToD, String... parts) { 
     Set<String> unique=new HashSet<String>(); 
     List<String> result=new ArrayList<String>(); 
     for (String part : parts){ 
      if (part==null || part.length()==0) continue; 
      part=compactSquares(part); 
      part=part.replaceAll("\\[(\\d)\\]","$1"); 
      if (part.indexOf("[0-9]")>=0){ 
       if (transform09ToD) part=part.replace("[0-9]","\\d"); 
      } 
      //[0-3][0-9]|4[0-9]=>[0-34][0-9] 
      //[023][0-9]|4[0-9]=>[0234][0-9] 
      //[02345789]=>[02-57-9] 
      Matcher m=secondCompact.matcher(part); 
      if (m.find()){ 
       part=m.group(1).replace("(","").replace(")","")+"["+m.group(2).replaceAll("[\\[\\]]","")+m.group(3).replaceAll("[\\[\\]]","")+"][0-9]"; 
      } 
      part=part.replaceAll("\\[(\\d)-\\1\\]","$1"); 
      if (unique.add(part)) result.add(part); 
     } 
     return result; 
    } 

    static String compactSquares(String src){ 
    boolean inSquares=false; 
    if (src.startsWith("[") && src.endsWith("]")){ 
     inSquares=true; 
     src=src.substring(1,src.length()-1); 
    } 
    StringBuffer sb=new StringBuffer(); 
    if (!src.contains("-")) { 
     List<Integer> digits=new ArrayList<Integer>(); 
     for (int i=0; i<src.length();i++){ 
     digits.add(Integer.parseInt(""+src.charAt(i))); 
     } 
     Collections.sort(digits); 
     for (Integer s : digits){ 
     sb.append(s); 
     } 
     src=sb.toString(); 
     sb.setLength(0); 
    } 
    int firstChar = -2; 
    int lastChar = -2; 
    int currentChar; 
    for (int i=0; i<src.length(); i++) { 
     currentChar=src.charAt(i); 
     if (currentChar == lastChar + 1) { 
     lastChar = currentChar; 
     continue; 
     } 
     if (currentChar == '-' && i+1 < src.length()) { 
     lastChar = src.charAt(i + 1) - 1; 
     continue; 
     } 
     flush(sb, firstChar, lastChar); 
     firstChar = currentChar; 
     lastChar = currentChar; 
    } 
    flush(sb, firstChar, lastChar); 
    return (inSquares?"[":"")+sb.toString()+(inSquares?"]":""); 
    } 

    private static void flush(StringBuffer sb, int firstChar, int lastChar) { 
    if (lastChar<=0) return; 
    if (firstChar==lastChar) { 
     sb.append((char)firstChar); 
     return; 
    } 
    if (firstChar+1==lastChar){ 
     sb.append((char)firstChar); 
     sb.append((char)lastChar); 
     return; 
    } 
    sb.append((char)firstChar); 
    sb.append('-'); 
    sb.append((char)lastChar); 
    } 

    static String glueParts(List<String> parts) { 
     if (parts==null || parts.isEmpty()) return ""; 
     if (parts.size()==1) return parts.get(0); 
     StringBuilder result=new StringBuilder(128); 
     for (String part : parts){ 
      result.append(part); 
      result.append("|"); 
     } 
     result.deleteCharAt(result.length()-1); 
     return result.toString(); 
    } 

    private String[] toParts() { 
    List<String> result=new ArrayList<String>(); 
    if (getNumberOfDigits(left)>2 || getNumberOfDigits(right)>2) { 
     result.add(startPart(left)); 
    } 
    long leftPart=left; 
    long rightPart=right; 
    if (!String.valueOf(left).matches("10*")) leftPart=toPower(left); 
    if (!String.valueOf(right).matches("10*")) rightPart=toPower(right)/10; 
    if (rightPart/leftPart>=10) { 
     result.add(speedUpPart(left, right)); 
    } 
    //for 1-2 digit process 
    if (getNumberOfDigits(left)==1 && getNumberOfDigits(right)==1){ 
     result.add("["+left+"-"+right+"]"); 
    } 
    else if (getNumberOfDigits(left)==1 && getNumberOfDigits(right)==2){ 
     if (0==Integer.parseInt(getMajorDigit(right))) { 
     result.add(getMajorDigit(left)+ 
        "["+ 
        getMajorDigit(getNumberWithoutMajorDigit(left))+ 
        "-"+ 
        getMajorDigit(getNumberWithoutMajorDigit(right))+ 
        "]"); 
     } 
     else if (1==Integer.parseInt(getMajorDigit(right))) { 
     result.add("["+ 
        getMajorDigit(getNumberWithoutMajorDigit(left))+ 
        "-9]"); 
     result.add(getMajorDigit(right)+ 
        "[0-"+ 
        getMajorDigit(getNumberWithoutMajorDigit(right))+ 
        "]"); 
     } 
     else if (2<=Integer.parseInt(getMajorDigit(right))) { 
     result.add("["+ 
        getMajorDigit(left)+ 
        "-9]"); 
     result.add("[1-"+ 
        (Integer.parseInt(getMajorDigit(right))-1)+ 
        "][0-9]"); 
     result.add(getMajorDigit(right)+ 
        "[0-"+ 
        getMajorDigit(getNumberWithoutMajorDigit(right))+ 
        "]"); 
     } 
     else throw new IllegalStateException(); 
    } 
    else if (getNumberOfDigits(left)==2 && getNumberOfDigits(right)==2){ 
     if (Integer.parseInt(getMajorDigit(left))==Integer.parseInt(getMajorDigit(right))) { 
     result.add(getMajorDigit(left)+ 
        "["+ 
        getMajorDigit(getNumberWithoutMajorDigit(left))+ 
        "-"+ 
        getMajorDigit(getNumberWithoutMajorDigit(right))+ 
        "]"); 
     } 
     else if (Integer.parseInt(getMajorDigit(left))+1==Integer.parseInt(getMajorDigit(right))) { 
     result.add(getMajorDigit(left)+ 
        "["+ 
        getMajorDigit(getNumberWithoutMajorDigit(left))+ 
        "-9]"); 
     result.add(getMajorDigit(right)+ 
        "[0-"+ 
        getMajorDigit(getNumberWithoutMajorDigit(right))+ 
        "]"); 
     } 
     else if (Integer.parseInt(getMajorDigit(left))+2<=Integer.parseInt(getMajorDigit(right))) { 
     result.add(getMajorDigit(left)+ 
        "["+ 
        getMajorDigit(getNumberWithoutMajorDigit(left))+ 
        "-9]"); 
     result.add("["+(Integer.parseInt(getMajorDigit(left))+1)+ 
        "-"+(Integer.parseInt(getMajorDigit(right))-1)+ 
        "][0-9]"); 
     result.add(getMajorDigit(right)+ 
        "[0-"+ 
        getMajorDigit(getNumberWithoutMajorDigit(right))+ 
        "]"); 
     } 
     else throw new IllegalStateException(); 
    } 
    else result.add(staticPart(right)); 
    result.add(breakPart(right)); 
    return result.toArray(new String[0]); 
    } 

    static String breakPart(final Long number) { 
    if (getNumberOfDigits(number)<=2) { 
     return ""; 
    } 
    StringBuilder result=new StringBuilder(256); 
    StringBuilder staticSection=new StringBuilder(32); 
    staticSection.append(getMajorDigit(number)); 
    for (int i=1; i<getNumberOfDigits(number)-1; i++){ 
     if (i!=1) result.append("|"); 
     result.append(staticSection.toString()); 
     staticSection.append(String.valueOf(number).charAt(i)); 
     final long nextDigit=Long.parseLong(""+String.valueOf(number).charAt(i))-1; 

     if (nextDigit<0) { 
     result.setLength(0); 
     result.append("|"); 
     continue; 
     } 
     if (nextDigit==0) result.append("0"); 
     else if (nextDigit==1) result.append("[01]"); 
     else result.append("[0-"+(nextDigit)+"]"); 
     final int numberOfRepeats=(getNumberOfDigits(number)-i-1); 
     if (numberOfRepeats==1) result.append("[0-9]"); 
     else result.append("[0-9]{"+numberOfRepeats+"}"); 
    } 
    //остаток - 2 последние цифры числа 
    if (result.length()>0) { 
     result.append("|"); 
     result.append(staticSection.toString()); 
     //последнюю цифру от 0 до нее 
     result.append("[0-"+Long.parseLong(number.toString().replaceFirst("\\d+(\\d)","$1"))+"]"); 
    } 
    if (result.length()>0) return result.toString().replace("||","|").replaceAll("^\\|",""); 
    return ""; 
    } 

    static String staticPart(final Long number) { 
    final long majorDigitMinus1=(Long.parseLong(getMajorDigit(number))-1); 
    if (majorDigitMinus1<=0) return ""; 
    if (majorDigitMinus1==2) return "[1"+majorDigitMinus1+"][0-9]{"+(getNumberOfDigits(number)-1)+"}"; 
    else if (majorDigitMinus1==1) return "1[0-9]{"+(getNumberOfDigits(number)-1)+"}"; 
    return "[1-"+majorDigitMinus1+"][0-9]{"+(getNumberOfDigits(number)-1)+"}"; 
    } 

    /** 
    * [1-9][0-9]{<X-1>,<Y-1>}, where X-number of digits of less number, Y-number of digits of greater number 
    */ 
    static String speedUpPart(Long left, Long right) { 
    //найти ближайшее до 0 то есть для 23 найти 100 для 777 найти 1000 
    //округленные до ближайшего 0 
    if (!String.valueOf(left).matches("10*")) left=toPower(left); 
    if (!String.valueOf(right).matches("10*")) right=toPower(right)/10; 
    final int leftPartRepeat=getNumberOfDigits(left)+(String.valueOf(left).matches("10*")?0:1)-1; 
    final int rightPartRepeat=getNumberOfDigits(right)+(String.valueOf(right).matches("10*")?0:1)-2; 
    if (getNumberOfDigits(left)==1 && getNumberOfDigits(right)==2) 
     return "[1-9]"; 
    else if (leftPartRepeat>=rightPartRepeat) 
     return "[1-9][0-9]{"+rightPartRepeat+"}"; 
    else 
     return "[1-9][0-9]{"+leftPartRepeat+","+rightPartRepeat+"}"; 
    } 

    private static long toPower(final Long number) { 
    final double dValue=Math.pow(10, getNumberOfDigits(number)); 
    final String value=String.format(Locale.US,"%24.0f",dValue); 
    return Long.parseLong(value.replaceFirst("\\s*(\\d+)(\\D\\d+)?","$1")); 
    } 

    private static int getNumberOfDigits(long number){ 
    return (String.valueOf(number).length()); 
    } 
    private static String getMajorDigit(long number){ 
    return (String.valueOf(number).substring(0,1)); 
    } 
    private static long getNumberWithoutMajorDigit(long number){ 
    return Long.parseLong(String.valueOf(number).replaceFirst("\\d(\\d+)","$1")); 
    } 

    /** 
    * f(<n>>2)=<major digit>(f(<n-1>)|[<major digit+1>-9][0-9]{<n-1>}) 
    */ 
    static String startPart(long number) { 
    int i=getNumberOfDigits(number); 
    if (i==1) { 
     if (number==9) return "9"; 
     else if (number==8) return "[89]"; 
     return "["+number+"-9]"; 
    } 
    final long majorPlusOne=Long.parseLong(getMajorDigit(number))+1; 
    final int numberOfDigitsMinusOne=getNumberOfDigits(number)-1; 
    String result = (majorPlusOne < 10 ? "(" : ""); 
    result+=getMajorDigit(number); 
    result+=startPart(getNumberWithoutMajorDigit(number)); 
    result+=result.indexOf("|")<0 && majorPlusOne<10 && majorPlusOne!=numberOfDigitsMinusOne && numberOfDigitsMinusOne>1?"{"+numberOfDigitsMinusOne+"}":""; 
    result+=(majorPlusOne < 10 
      ? "|[" + majorPlusOne + "-9][0-9]"+(numberOfDigitsMinusOne > 1 ? "{" + numberOfDigitsMinusOne + "}" : "") 
      : ""); 
    result+=(majorPlusOne < 10 ? ")" : ""); 
    return result; 
    } 

    private void parseAndCheck() { 
    Matcher matcher=pattern.matcher(src); 
    matcher.find(); 
    try{ 
     left=Long.parseLong(matcher.group(1)); 
     right=Long.parseLong(matcher.group(2)); 
    } 
    catch(Exception ex){ 
     left=right+1; 
    } 
    if (left>right){ 
     throw new IllegalArgumentException(MessageFormat.format(invalidArgumentEmpty, 
                   src, 
                   "Left part must be less than right one.")); 
    } 
    } 

    public String getPattern() { 
    return result; 
    } 

    public static void main(String[] args) { 
     System.err.println(new NumberDiapasone2RegExp(args[0]).getPattern()); 
    } 
} 
+4

張貼了一大段代碼,沒有解釋什麼是不被認爲是好的做法。 – venerik

+0

不知道這是否工作。我加入了'199-200'並得到了'(199 | [2-9] [0-9] {2})| 1 [0-9] {2} | 200'。它的'[2-9] [0-9] {2}'部分將匹配200-999 –

1

您可以使用以下格式編寫正則表達式來解決您的問題。 假設你的範圍是0-15。

"^DX [0-9]|1[0-5]$" 

你甚至可以通過附加字符串使其變爲動態範圍。

-1

我也試圖找到有效範圍的分鐘 [0-60]爲我工作。

我使用jdk 1.8雖然

+1

您的表達式[0-60]與Java中的[0-6]類似,範圍從字符到字符,不是號碼。它只會匹配從0到6的單個數字:https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html –

+0

哦。在JavaScript中工作得很好,但 – Tarun

+1

不,它不。在https://jsfiddle.net/b34o3371/1/上演示 –