是否有任何库用于解析Java中的“数字表达式”,如1,2-9,33-

我不认为这很难,只是单调乏味:一些小的免费(如在啤酒中)库,我可以放入一个像1,2-9,33这样的字符串,它可以告诉我一个给定的数字是否匹配表达。 就像大多数程序在其打印范围对话框中一样。 仅用于匹配奇数或偶数的特殊函数,或匹配每个2 mod 5(或类似的数字)的数字将是不错的,但不是必需的。

我必须在此列表上执行的唯一操作是范围是否包含给定(非负)整数值; 当然,更多的操作,如最大/最小值(如果它们存在)或迭代器会很好。

如果有人输入1-10000000但是我将要查询的唯一数字是12345,那么它不会占用大量内存需要什么:-)

(为了实现它,我会将列表解析成几个(最小/最大/值/ mod)对,例如1,10,0,1表示1-10或11,33,1,2表示1-33odd,或12 ,62,2,10表示12-62 / 10(即12,22,32,…,62),然后检查所有间隔的每个数字。使用Integer.MaxValue等打开间隔。如果没有库,任何想法做得更好/更有效?)

我决定自己编码。 使用风险自负:-)

 /* * NumberExpression.java - a simple number expression parser * * Copyright (c) 2010 Michael Schierl * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND THE CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package numberexpression; /** * An expression that matches nonnegative numbers. This supports cron-like * expressions, like 1,3-6,100-200,666,1000-3000/5,400-/7, * -100,102- or *. Odd or even numbers can be * matched either by cron's step syntax, or by suffixing a simple range * (without step values) with e or o. * * @author Michael Schierl */ public class NumberExpression { private final NumberRange[] ranges; private final int min, max; /** * Create a new {@link NumberExpression}. * * @param pattern * the expression pattern. * @throws IllegalArgumentException * if the pattern is malformed */ public NumberExpression(String pattern) { String[] parts = pattern.toLowerCase().split(",",-1); ranges = new NumberRange[parts.length]; int min = Integer.MAX_VALUE, max = 0; for (int i = 0; i < ranges.length; i++) { String part = parts[i]; try { if (part.equals("*")) { ranges[i] = new NumberRange(0, Integer.MAX_VALUE, 0, 1); } else if (part.matches("\\*/\\d+")) { ranges[i] = new NumberRange(0, Integer.MAX_VALUE, 0, Integer.parseInt(part.substring(2))); } else if (part.matches("\\d+")) { int value = Integer.parseInt(part); ranges[i] = new NumberRange(value, value, 0, 1); } else if (part.matches("\\d*-\\d*")) { String[] limits = part.split("-", -1); int from = limits[0].length() == 0 ? 0 : Integer.parseInt(limits[0]); int to = limits[1].length() == 0 ? Integer.MAX_VALUE : Integer.parseInt(limits[1]); if (to < from) throw new IllegalArgumentException("Invalid pattern: " + part); ranges[i] = new NumberRange(from, to, 0, 1); } else if (part.matches("\\d*-\\d*/\\d+")) { String[] rangeAndModulus = part.split("/", -1); String[] limits = rangeAndModulus[0].split("-", -1); int from = limits[0].length() == 0 ? 0 : Integer.parseInt(limits[0]); int to = limits[1].length() == 0 ? Integer.MAX_VALUE : Integer.parseInt(limits[1]); int modulus = Integer.parseInt(rangeAndModulus[1]); if (to < from) throw new IllegalArgumentException("Invalid pattern: " + part); ranges[i] = new NumberRange(from, to, from % modulus, modulus); } else if (part.matches("\\d*-\\d*[eo]")) { String[] limits = part.substring(0, part.length() - 1).split("-", -1); int from = limits[0].length() == 0 ? 0 : Integer.parseInt(limits[0]); int to = limits[1].length() == 0 ? Integer.MAX_VALUE : Integer.parseInt(limits[1]); if (to < from) throw new IllegalArgumentException("Invalid pattern: " + part); ranges[i] = new NumberRange(from, to, part.charAt(part.length() - 1) == 'o' ? 1 : 0, 2); } else { throw new IllegalArgumentException("Invalid pattern: " + part); } max = Math.max(max, ranges[i].getMax()); min = Math.min(min, ranges[i].getMin()); } catch (NumberFormatException ex) { throw new IllegalArgumentException("Invalid pattern: " + part); } } this.max = max; this.min = min; } /** * Check whether this number expression matches the given number. * * @param number * the number to check against * @return whether the expression matches the number */ public boolean matches(int number) { if (number < min || number > max) return false; for (int i = 0; i < ranges.length; i++) { if (ranges[i].matches(number)) return true; } return false; } /** * Return the minimum number that can be matched. */ public int getMinimum() { return min; } /** * Return the maximum number that can be matched. */ public int getMaximum() { return max; } private static class NumberRange { private final int min, max, remainder, modulus; NumberRange(int min, int max, int remainder, int modulus) { this.min = min; this.max = max; this.remainder = remainder; this.modulus = modulus; } boolean matches(int number) { return number >= min && number <= max && number % modulus == remainder; } int getMin() { return min; } int getMax() { return max; } } } 

听起来只是编码它会更容易。

这是支持您的愿望范围部分的python代码。

 >>> def f(n, pattern): ... ranges = [r.split('-') for r in pattern.split(',')] ... for a,b in ranges: ... if (not a or int(a) <= n) and (not b or int(b) >= n): ... return True ... return False ... >>> f(4, '-1,2-9,33-') True >>> f(11, '-1,2-9,33-') False >>> f(100, '-1,2-9,33-') True >>> 

它以线性时间运行到字符串长度。 如果将模式编译为IntervalTree,则可以进行对数。 内存使用量始终是线性的。