使用正则表达式检查数字范围

时间:2011-10-22 18:25:33

标签: java regex numbers range

我正在使用正则表达式来验证字符串中的某种格式。这个字符串将成为游戏的规则。

示例:“DX 3”根据规则可以,但“DX 14”也可以正常...我知道如何查看字符串并找到一个或多个“数字”,所以问题是正则表达式也匹配34,这个数字超出了规则的“范围”......

我是否遗漏了有关正则表达式的事情?或者这根本不可能?

5 个答案:

答案 0 :(得分:35)

不幸的是,在正则表达式中定义范围并不容易。如果你要使用1-23的范围,你最终会得到这样的正则表达式:

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

说明:

  1. 值为1-9
  2. 或值以1开头,后跟0-9
  3. 或者值以2开头,然后是0-3

答案 1 :(得分:3)

它不是那么短,也不灵活。

如果你搜索1到19,你可以搜索“DX 1?[0-9]”,但是如果它没有以数字边界结束,很快就会变得丑陋,并且改变了规则不灵活。

将字符串拆分为空白,然后使用x> 0和x< 24更好理解,更灵活。

答案 2 :(得分:1)

您可以使用以下格式编写解决问题的正则表达式。 假设你的范围是0-15。

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

您甚至可以通过附加字符串来使其动态化,具体取决于您的范围。

答案 3 :(得分:-3)

    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 :(得分:-3)

我还试图找到一系列有效范围的分钟 [0-60]为我工作。

我正在使用jdk 1.8但