从字符串高级解析数值范围

时间:2012-10-22 12:40:07

标签: java regex

我正在使用Java来解析用户输入的字符串,表示单个数值或范围。用户可以输入以下字符串:

10-19

他的目的是使用10-19中的整数 - > 10,11,12...19

用户还可以指定数字列表:

10,15,19

或以上的组合:

10-19,25,33

是否有一种方便的方法(可能基于正则表达式)来执行此解析?或者我必须使用String.split()拆分字符串,然后手动迭代特殊符号(在这种情况下为','和' - ')?

4 个答案:

答案 0 :(得分:15)

我会这样做:

  1. 使用,作为分隔符进行拆分。
  2. 如果它与这个正则表达式匹配:^(\\d+)-(\\d+)$,那么我知道我有一个范围。然后我会提取数字并创建我的范围(确保第一个数字低于第二个数字可能是一个好主意,因为你永远不会知道......)。然后你采取相应的行动。
  3. 如果它与这个正则表达式匹配:^\\d+$我知道我只有一个数字,所以我有一个特定的页面。然后我会采取相应的行动。

答案 1 :(得分:8)

这个经过测试(并且完全注释)的正则表达式解决方案符合OP要求:

Java正则表达式解决方案

// TEST.java 20121024_0700
import java.util.regex.*;
public class TEST {
    public static Boolean isValidIntRangeInput(String text) {
        Pattern re_valid = Pattern.compile(
            "# Validate comma separated integers/integer ranges.\n" +
            "^             # Anchor to start of string.         \n" +
            "[0-9]+        # Integer of 1st value (required).   \n" +
            "(?:           # Range for 1st value (optional).    \n" +
            "  -           # Dash separates range integer.      \n" +
            "  [0-9]+      # Range integer of 1st value.        \n" +
            ")?            # Range for 1st value (optional).    \n" +
            "(?:           # Zero or more additional values.    \n" +
            "  ,           # Comma separates additional values. \n" +
            "  [0-9]+      # Integer of extra value (required). \n" +
            "  (?:         # Range for extra value (optional).  \n" +
            "    -         # Dash separates range integer.      \n" +
            "    [0-9]+    # Range integer of extra value.      \n" +
            "  )?          # Range for extra value (optional).  \n" +
            ")*            # Zero or more additional values.    \n" +
            "$             # Anchor to end of string.           ", 
            Pattern.COMMENTS);
        Matcher m = re_valid.matcher(text);
        if (m.matches())    return true;
        else                return false;
    }
    public static void printIntRanges(String text) {
        Pattern re_next_val = Pattern.compile(
            "# extract next integers/integer range value.    \n" +
            "([0-9]+)      # $1: 1st integer (Base).         \n" +
            "(?:           # Range for value (optional).     \n" +
            "  -           # Dash separates range integer.   \n" +
            "  ([0-9]+)    # $2: 2nd integer (Range)         \n" +
            ")?            # Range for value (optional). \n" +
            "(?:,|$)       # End on comma or string end.", 
            Pattern.COMMENTS);
        Matcher m = re_next_val.matcher(text);
        String msg;
        int i = 0;
        while (m.find()) {
            msg = "  value["+ ++i +"] ibase="+ m.group(1);
            if (m.group(2) != null) {
                msg += " range="+ m.group(2);
            };
            System.out.println(msg);
        }
    }
    public static void main(String[] args) {
        String[] arr = new String[] 
                { // Valid inputs:
                    "1", 
                    "1,2,3",
                    "1-9",
                    "1-9,10-19,20-199",
                    "1-8,9,10-18,19,20-199",
                  // Invalid inputs:
                    "A", 
                    "1,2,",
                    "1 - 9",
                    " ",
                    ""
                };
        // Loop through all test input strings:
        int i = 0;
        for (String s : arr) {
            String msg = "String["+ ++i +"] = \""+ s +"\" is ";
            if (isValidIntRangeInput(s)) {
                // Valid input line
                System.out.println(msg +"valid input. Parsing...");
                printIntRanges(s);
            } else {
                // Match attempt failed
                System.out.println(msg +"NOT valid input.");
            } 
        }
    }
}

输出:

r'''
String[1] = "1" is valid input. Parsing...
  value[1] ibase=1
String[2] = "1,2,3" is valid input. Parsing...
  value[1] ibase=1
  value[2] ibase=2
  value[3] ibase=3
String[3] = "1-9" is valid input. Parsing...
  value[1] ibase=1 range=9
String[4] = "1-9,10-19,20-199" is valid input. Parsing...
  value[1] ibase=1 range=9
  value[2] ibase=10 range=19
  value[3] ibase=20 range=199
String[5] = "1-8,9,10-18,19,20-199" is valid input. Parsing...
  value[1] ibase=1 range=8
  value[2] ibase=9
  value[3] ibase=10 range=18
  value[4] ibase=19
  value[5] ibase=20 range=199
String[6] = "A" is NOT valid input.
String[7] = "1,2," is NOT valid input.
String[8] = "1 - 9" is NOT valid input.
String[9] = " " is NOT valid input.
String[10] = "" is NOT valid input.
'''

请注意,此解决方案仅演示如何验证输入行以及如何从每行解析/提取值组件。它没有进一步验证对于范围值,第二个整数大于第一个整数。但是,可以轻松添加此逻辑检查。

编辑次数:2012-10-24 07:00 修正索引i从零开始计算。

答案 2 :(得分:1)

您可以使用

strinput = '10-19,25,33'
eval(cat(2,'[',strrep(strinput,'-',':'),']'))

最好是包含一些输入检查,负数也会给这个方法带来问题。

答案 3 :(得分:-2)

在最简单的方法中,你可以使用邪恶的eval来实现这个

A = eval('[10:19,25,33]')

A =

   10    11    12    13    14    15    16    17    18    19    25    33

当然,在你这样做之前,你应该三思而后行。特别是如果这是用户提供的字符串!想象一下,如果用户提供了任何其他命令会发生什么......

eval('!rm -rf /')

你必须确保除了你想要的东西之外别无其他。您可以通过regexp执行此操作。