2011-10-22 4 views
14

J'utilise une expression régulière pour valider un certain format dans une chaîne. Cette chaîne deviendra une règle pour un jeu. Exemple: "DX 3" est OK selon la règle, mais "DX 14" pourrait être OK aussi ... Je sais comment regarder la chaîne et trouver un ou plusieurs "nombres", donc le problème est que la regex correspondra aussi à 34, et que ce nombre est hors de "portée" pour la règle ...Vérification d'une plage de nombres avec des expressions régulières

Ai-je manqué quelque chose à propos de la regex pour faire cela? Ou est-ce pas possible du tout?

+0

Quelle est la gamme dont vous avez besoin? – npinti

Répondre

29

Malheureusement, il n'y a pas de moyen facile de définir des plages dans regex. Si vous êtes d'utiliser la gamme 1-23 vous vous retrouverez avec une expression régulière comme ceci:

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

Explication:

  1. Soit la valeur est 1-9
  2. ou la valeur commence avec 1 et est suivi d'un 0-9
  3. ou la valeur commence par 2 et est suivi d'un 0-3
+0

Merci beaucoup! J'essayais cela mais je n'utilisais pas le "()" – mrs1986

3

Il est pas court, et non flexible. Si vous recherchez 1 à 19, vous pouvez rechercher "DX 1? [0-9]", par exemple, mais s'il ne se termine pas à une limite de nombre, il deviendra moche assez rapidement et changera les règles ne sont pas flexibles.

Diviser la chaîne sur le blanc, puis en utilisant x> 0 et x < 24 est mieux compris et plus flexible.

-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

Affichage d'un gros morceau de code sans explication ce qui n'est jamais considéré comme une bonne pratique. – venerik

+0

ne sais pas si cela fonctionne. J'ai mis '199-200' et j'ai' '(199 | [2-9] [0-9] {2}) | 1 [0-9] {2} | 200'. La partie '[2-9] [0-9] {2}' correspondrait à 200-999 –

1

Vous pouvez utiliser le format suivant pour écrire une expression régulière résolvant votre problème. Supposons que votre plage soit comprise entre 0 et 15.

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

Vous pouvez même le rendre dynamique en fonction de votre plage en ajoutant des chaînes.

-1

J'essayais également de trouver une gamme de plage valide pour les minutes [0-60] travaillé pour moi. J'utilise jdk 1.8 par

+1

Votre expression [0-60] est similaire à [0-6] dans Java car les plages vont d'un caractère à l'autre, pas de nombre à nombre. Il ne correspondra qu'à un seul chiffre de 0 à 6: https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html –

+0

Oh. Fonctionne très bien en javascript si – Tarun

+1

Non, il ne le fait pas. Démonstration à https://jsfiddle.net/b34o3371/1/ –

Questions connexes