2011-10-22 9 views
14

Tôi đang sử dụng cụm từ thông dụng để xác thực một định dạng nhất định trong chuỗi. Chuỗi này sẽ trở thành quy tắc cho trò chơi.Kiểm tra phạm vi số với cụm từ thông dụng

Ví dụ: "DX 3" là OK theo quy tắc, nhưng "DX 14" cũng có thể OK ... Tôi biết cách xem chuỗi và tìm một hoặc nhiều "số", do đó, vấn đề là rằng regex cũng sẽ phù hợp với 34, và con số này nằm ngoài "phạm vi" cho quy tắc ...

Tôi có thiếu thứ gì đó về regex để làm điều này không? Hay điều này là không thể?

+0

Phạm vi bạn cần là gì? – npinti

Trả lời

29

Rất tiếc, không có cách nào dễ dàng để xác định phạm vi trong regex. Nếu bạn đang sử dụng khoảng 1-23 bạn sẽ kết thúc với một regex như thế này:

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

Giải thích:

  1. Hoặc giá trị là 1-9
  2. hoặc giá trị bắt đầu với 1 và được theo sau với một 0-9
  3. hoặc giá trị bắt đầu với 2 và được theo sau với một 0-3
+0

Cảm ơn rất nhiều! Tôi đã cố gắng nhưng tôi đã không sử dụng "()" – mrs1986

3

Nó không phải là ngắn, và không linh hoạt.

Nếu bạn tìm kiếm từ 1 đến 19, bạn có thể tìm kiếm "DX 1? [0-9]", nhưng nếu nó không kết thúc ở ranh giới số, nó sẽ xấu xí khá sớm và thay đổi các quy tắc không linh hoạt.

Tách chuỗi tại ô trống và sau đó sử dụng x> 0 và x < 24 thì tốt hơn để hiểu và linh hoạt hơn.

-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

Đăng một đoạn mã lớn mà không có giải thích những gì để không bao giờ được coi là thực hành tốt. – venerik

+0

không chắc chắn nếu điều này hoạt động. Tôi đặt vào '199-200' và nhận' (199 | [2-9] [0-9] {2}) | 1 [0-9] {2} | 200'. Phần '[2-9] [0-9] {2}' của nó sẽ khớp với 200-999 –

1

Bạn có thể sử dụng định dạng sau để viết biểu thức chính quy giải quyết vấn đề của mình. Giả sử phạm vi của bạn là 0-15.

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

Bạn thậm chí có thể làm cho nó hoạt động tùy thuộc vào phạm vi của bạn bằng cách thêm chuỗi.

-1

Tôi cũng đang cố gắng tìm một dải phạm vi hợp lệ cho phút [0-60] đã làm việc cho tôi.

Tôi đang sử dụng jdk 1.8 mặc dù

+1

Biểu thức của bạn [0-60] tương tự như [0-6] trong Java vì phạm vi từ ký tự đến ký tự, không phải là số. Nó sẽ chỉ khớp với một chữ số duy nhất từ ​​0 đến 6: https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html –

+0

Ồ. Hoạt động khá tốt trong javascript mặc dù – Tarun

+1

Không có nó không. Trình diễn tại https://jsfiddle.net/b34o3371/1/ –