【问题标题】:Passing multiple delimiters to StringTokenizer constructor将多个分隔符传递给 StringTokenizer 构造函数
【发布时间】:2020-01-08 14:20:25
【问题描述】:

我已经看到将多个分隔符(例如'.'、'?'、'!')传递给 StringTokenizer 构造函数的语法是:

StringTokenizer obj=new StringTokenizer(str,".?!");

我没有得到的是,我已将所有定界符用双引号括起来,所以这不会使它成为字符串而不是单独的 人物。 StringTokenizer 类如何将它们识别为单独的字符?为什么是 ”。?!”不被视为单个分隔符?

【问题讨论】:

  • 因为这就是文档所说的。我不确定是什么问题。
  • 我的意思是,分隔符可以是字符串而不是单个字符吗?例如。可以将“abc”视为单个分隔符吗?
  • @UserKunal123 与StringTokenizer - 没有。 String#split - 是的。看我的回答。

标签: java string tokenize stringtokenizer


【解决方案1】:

StringTokenizer 是一个遗留类,出于兼容性原因保留,但不鼓励在新代码中使用它。

所以忘了它。

建议任何寻求此功能的人使用 String 的 split 方法或 java.util.regex 包。

所以请改用String#split

String[] elements = str.split("\\.\\?!"); // treats ".?!" as a single delimiter
String[] elements2 = str.split("[.?!]"); // three delimiters 

如果您想念StringTokenizerEnumeration 自然,请获取Iterator

Iterator<String> iterator = Arrays.asList(elements).iterator();
while (iterator.hasNext()) {
  String next = iterator.next();
  // ...
}

StringTokenizer 类如何将它们识别为单独的字符?

这是一个实现细节,您不必担心。 There are a couple of ways to do that. 他们使用String#charAt(int)String#codePointAt(int)

为什么是“.?!”不被视为单个分隔符?

这就是他们做出的选择:“我们将采用一个字符串,我们将在那里寻找分隔符s。” Javadoc 说明了这一点。

 *
 * @param   str            a string to be parsed.
 * @param   delim          the delimiters.
 * @param   returnDelims   flag indicating whether to return the delimiters
 *                         as tokens.
 * @exception NullPointerException if str is <CODE>null</CODE>
 */
public StringTokenizer(String str, String delim, boolean returnDelims) {

【讨论】:

    【解决方案2】:

    StringTokenizer 就是这样定义的。看看javadoc吧

    为指定的字符串构造一个字符串标记器。 delim 参数中的所有字符都是用于分隔标记的分隔符

    同样在源代码中你会发现delimiterCodePoints字段描述如下

    /**
     * When hasSurrogates is true, delimiters are converted to code
     * points and isDelimiter(int) is used to determine if the given
     * codepoint is a delimiter.
     */
    private int[] delimiterCodePoints;
    

    所以基本上每个delimiters 字符都被转换为存储在数组中的int 代码 - 然后使用数组来决定字符是否为分隔符

    【讨论】:

    • 我明白了..所以分隔符可以是字符串而不是单个字符吗?
    • 那么你需要使用 StringTokenizer 以外的其他东西 - 看看这个主题:stackoverflow.com/questions/12215598/…
    • 我明白了,所以 StringTokenizer 只将字符识别为分隔符。实际上我可以使用 Split[] 函数,但是我们学校的教学大纲限制了它的使用。无论如何,这消除了我的困惑。
    【解决方案3】:

    确实,您传递的是单个字符串而不是单个字符,但该字符串的处理取决于StringTokenizerStringTokenizer 从分隔符字符串中获取每个字符,并将每个字符用作分隔符。这样,您可以在多个不同的分隔符上拆分字符串,而无需多次运行分词器。

    您可以查看此函数 here 的文档,其中指出:

    delim 参数中的字符是分隔标记的分隔符。

    如果这个参数什么都不传入,就是defaults to" \t\n\r\f",基本上就是空格。

    【讨论】:

      【解决方案4】:

      StringTokenizer 类如何将它们识别为单独的字符?

      String 中有一个方法叫做charAtcodePointAt,它返回索引处的字符或代码点:

      "abc".charAt(0) // 'a'
      

      StringTokenizer 的实现将在某些时候在传入的分隔符上使用这两种方法。在我的 JDK 版本中,分隔符字符串的代码点被提取并添加到数组 delimiterCodePoints 中,该方法由构造函数调用,名为 setMaxDelimCodePoint

      私人无效 setMaxDelimCodePoint() { // ...

          if (hasSurrogates) {
              delimiterCodePoints = new int[count];
              for (int i = 0, j = 0; i < count; i++, j += Character.charCount(c)) {
                  c = delimiters.codePointAt(j); <--- notice this line
                  delimiterCodePoints[i] = c;
              }
          }
      }
      

      然后在isDelimiter方法中访问这个数组,判断一个字符是否为分隔符:

      private boolean isDelimiter(int codePoint) {
          for (int i = 0; i < delimiterCodePoints.length; i++) {
              if (delimiterCodePoints[i] == codePoint) {
                  return true;
              }
          }
          return false;
      }
      

      当然,这不是设计 API 的唯一方式。构造函数本可以接受 char 数组作为分隔符,但我没有资格说设计者为什么这样做。

      为什么是“.?!”不被视为单个分隔符?

      StringTokenizer 仅支持单字符分隔符。如果你想要一个字符串作为分隔符,你可以使用ScannerString.split 代替。对于这两种情况,分隔符都表示为正则表达式,因此您必须改用"\\.\\?!"。你可以了解更多关于正则表达式here

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-07
        • 2011-09-24
        • 2012-01-15
        • 1970-01-01
        • 2012-08-13
        相关资源
        最近更新 更多