【问题标题】:Java - Statically defined character listsJava - 静态定义的字符列表
【发布时间】:2012-04-06 00:34:59
【问题描述】:

在任何标准库中是否有字符类(字母、数字、字母数字)的定义?我正在检查一个字符串是否只包含字母数字字符或冒号:

StringUtils.containsOnly(input, ALPHA_NUMERIC + ":");

我可以自己定义 ALPHA_NUMERIC,但似乎通用字符类会在标准库中定义,尽管我一直找不到定义。

编辑:我确实考虑过正则表达式,但对于我的特定用例,执行时间很重要,简单的扫描更有效。

编辑:以下是测试结果,使用 Regex、CharMatcher 和简单扫描(对每个测试使用相同的有效/无效输入字符串集):

有效输入字符串:

CharMatcher,运行次数:1000000,有效字符串:true,时间(毫秒):1200

正则表达式,运行次数:1000000,有效字符串:true,时间(毫秒):909

扫描,运行次数:1000000,有效字符串:true,时间(毫秒):96

无效的输入字符串:

CharMatcher,运行次数:1000000,有效字符串:false,时间(毫秒):277

正则表达式,运行次数:1000000,有效字符串:false,时间(毫秒):253

扫描,运行次数:1000000,有效字符串:false,时间(毫秒):36

这是执行扫描的代码:

public boolean matches(String input) {
    for(int i=0; i<input.length(); i++) {
        char c = input.charAt(i);
        if( !Character.isLetterOrDigit(c) && c != ':') {
            return false;
        }
    }
    return true;
}

编辑:我重新编译为独立程序(我正在通过 eclipse 运行):

CharMatcherTester,运行次数:1000000,有效字符串:true,时间(毫秒):418

RegexTester,运行次数:1000000,有效字符串:true,时间(毫秒):812

ScanTester,运行次数:1000000,有效字符串:true,时间(毫秒):88

CharMatcherTester,运行次数:1000000,有效字符串:false,时间(毫秒):142

RegexTester,运行次数:1000000,有效字符串:false,时间(毫秒):223

ScanTester,运行次数:1000000,有效字符串:false,时间(毫秒):32

来源:https://bitbucket.org/jdeveloperw/testing(这是我第一次在 SO 上发布测试结果,感谢 cmets。)

【问题讨论】:

标签: java string character-class


【解决方案1】:

您最好的选择可能是正则表达式Pattern

应该匹配:

[\p{Alnum}:]*
  • \p{Alnum} - ASCII 字母数字
  • [] - 字符类(里面的任何字符都会匹配一个字符)
  • : - 文字:
  • * - 0 个或更多

如果都是字母数字(或:)。

您可以使用matches 或预编译正则表达式。

【讨论】:

  • 我确实想过使用正则表达式,但对于我的特定用例,执行时间很重要,简单的扫描更有效。
  • 基准测试是个好主意;我会比较 CharMatcher、Regex 和一次扫描,并在我有一点空闲时间时发布结果。
  • 基准测试结果已发布。我还可以提供我用于测试的完整代码。
  • 来源:bitbucket.org/jdeveloperw/testing(我将非常感谢任何关于如何改进基准测试的 cmets。)
【解决方案2】:

当您谈论regex 时,它确实存在,在这种情况下,字符类\w 就代表了这一点。这就是 String 类有 matches 方法的原因。

edit: StringUtils 类可能早于Java 1.4 添加matches 方法时。 Apache Commons 类提供的许多功能已被合并到标准库中。当您必须使用旧版本的 Java 或使用标准库中没有的东西时,它们仍然很有用,但这似乎不是其中一种情况。

【讨论】:

  • 没有。这包括下划线,但不包括冒号。
  • 嗯,是的,您必须像 OP 当前所做的那样,将冒号添加到您的模式中。但你对下划线的看法是对的,我忘记了。
【解决方案3】:

试试这个,使用正则表达式:

boolean containsOnlyAlphanumeric = input.matches("[\\p{Alnum}:]+");

编辑:

为了获得最佳性能,您可以预编译模式,将其存储在静态定义的模式常量中,并在必要时重用它:

// part of the class declaration
private static final Pattern ALPHANUMERIC_PLUS_COLON = Pattern.compile("[\\p{Alnum}:]+");

// whenever you need to check if the input matches the pattern
boolean containsOnlyAlphanumeric = ALPHANUMERIC_PLUS_COLON.matcher(input).matches();

我同意 Matthew Flaschen 的观点,您不应该立即丢弃正则表达式,一个精心构建的预编译正则表达式可以与检查输入字符串中所有可能的有效字符的扫描一样快,甚至更快。先做基准测试!

【讨论】:

  • ^ 和 $ 是 Java 中行的开头和结尾,而不是输入。
  • @MatthewFlaschen 它已修复。没错,^$ 在使用 matches() 时是不必要的
  • 谢谢,不确定它是否默认匹配整个字符串。
  • @MatthewFlaschen 是的,确实如此。它在Matcher 中调用matches() 方法,javadocs 声明它“尝试将整个区域与模式匹配”。
【解决方案4】:

Guava's CharMatcher 几乎是正是您所要求的。这是wiki article。 (披露:我为 Guava 做出了贡献。)

CharMatcher matcher = CharMatcher.JAVA_LETTER_OR_DIGIT.or(
  CharMatcher.is(':'));
return matcher.matchesAllOf(string);

【讨论】:

    【解决方案5】:

    正则表达式匹配可以完成这项工作。例如 MyString.matches("[a-zA-Z0-9:]*");

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-25
      相关资源
      最近更新 更多