【问题标题】:Java arrays - split() with user-specified delimitersJava 数组 - 带有用户指定分隔符的 split()
【发布时间】:2015-10-06 21:43:24
【问题描述】:

我正在尝试编写一个简单的程序,它接受两个用户输入:一个要拆分的字符串和一个指定一个或多个分隔符的字符串。该程序应该打印一个字符串数组,该数组由拆分的子字符串和分隔符组成。我必须实现 public static String[] split(String s, String regex)

如果要拆分的字符串是

cd#34#abef#1256

我当前的代码正确输出

[cd, 34, abef, 1256]

我需要输出的是

[cd, #, 34, abef, #, 1256]

如果要拆分的字符串有两个用户指定的分隔符怎么办

cd?34?abef#1256

我怎样才能把它拆分成这样的样子

[cd, ?, 34, ?, abef, #, 1256]

我之前研究过的问题都没有使用用户指定的字符串和分隔符。

这是我当前的代码:

import java.util.Arrays;
import java.util.Scanner;

public class StringSplit
{
    public static void main(String[] args)
    { 
        Scanner scan = new Scanner(System.in);
        System.out.print("Enter a string: ");
        String str = scan.next();
        System.out.print("Specify delimiter(s): ");
        String del = scan.next();
        String[] result = split(str, del);
        System.out.print(Arrays.toString(result));
    }

    public static String[] split(String s, String regex)
    {
        String[] myString = s.split(regex);
        return myString;
    }
}

【问题讨论】:

  • 我不认为他们是任何标准的 libray 方式来做到这一点。您将不得不实施自己的方式。
  • @kan,我调查了那个问题,这是针对不作为用户输入的字符串和分隔符的解决方案。
  • 需要更多说明 - 用户可以指定多字符分隔符吗?以及用户如何在他们的规范中分隔分隔符
  • 是的,提示时用户可以。他们应该能够输入“cd?34?abef#1256”,然后输入“?#”并得到[cd, ?, 34, ?, abef, #, 1256]

标签: java regex string split


【解决方案1】:

您可以使用这个基于前瞻和后瞻的正则表达式进行拆分:

(?<=#)|(?=#)

这意味着在下一个字符为# 或前一个字符为# 的位置拆分

对于多个分隔符:

(?<=[?#])|(?=[?#])

RegEx Demo

您的 Java 方法可以是这样的:

public static String[] split(String s, String d) {
    String del = Pattern.quote(d);
    String[] myString = s.split("(?<=[" + del + "])|(?=[" + del + "])");
    return myString;
}

并将其称为:

System.out.println(
   Arrays.toString(split("aa{bb}(cc)[dd]ee#ff...gg?hh*+ii", "#.?*+-[](){}"))
);

输出:

[aa, {, bb, }, (, cc, ), [, dd, ], ee, #, ff, ., ., ., gg, ?, hh, *, +, ii]

【讨论】:

  • 适用于以下分隔符:#.?*+-[](){}
  • 现在检查更新的代码以及使用#.?*+-[](){}作为分隔符。
  • 不确定您是否可以在括号 [] 内使用 quote()。很高兴知道。
【解决方案2】:

split() 根据定义排除了分隔符,因此除非您使用零宽度的先行/后行组,否则您不能使用它,即使这样您也可能会遇到特殊字符的问题。

自己动手:

public static List<String> split(String text, String delimiters) {
    List<String> result = new ArrayList<>();
    int start = 0;
    for (int i = 0; i < text.length(); i++)
        if (delimiters.indexOf(text.charAt(i)) != -1) {
            if (start < i)
                result.add(text.substring(start, i));
            result.add(text.substring(i, i + 1));
            start = i + 1;
        }
    if (start < text.length())
        result.add(text.substring(start));
    return result;
}

如果需要返回值为String[],则更改return语句:

    return result.toArray(new String[result.size()]);

测试

System.out.println(split("cd#34#abef#1256", "#"));
System.out.println(split("cd?34?abef#1256", "#?"));
System.out.println(split("aa{bb}(cc)[dd]ee#ff...gg?hh*+ii", "#.?*+[](){}"));

输出

[cd, #, 34, #, abef, #, 1256]
[cd, ?, 34, ?, abef, #, 1256]
[aa, {, bb, }, (, cc, ), [, dd, ], ee, #, ff, ., ., ., gg, ?, hh, *, +, ii]

注意:第三个测试用例可能会在任何尝试使用正则表达式的实现上失败。

【讨论】:

    【解决方案3】:

    您可以直接使用正则表达式和循环,如下所示:

    List<String> parts = new ArrayList<>();
    Pattern p = Pattern.compile("(#|\\?|[^#\\?]+)");
    Matcher m = p.matcher(s);
    while(m.find()) {
      parts.add(m.group(1));
    }
    

    请注意,正则表达式只是一个字符串。如果要使用自定义分隔符,可以动态创建模式。

    【讨论】:

      【解决方案4】:

      使用 char[] 并比较每个 char 的简单解决方案:

      public static void main(String[] args)
      { 
          // example string
          String str = "vv*aabb?eegg?fff";
          char[] chars=str.toCharArray();
      
          // list of delimiters
          List<Character> delimiters = new ArrayList<Character>();
          delimiters.add('*');
          delimiters.add('?');
          StringBuilder sb=new StringBuilder();
      
          for(int i=0 ; i<chars.length;i++){
              if (delimiters.contains(chars[i])){
                  // if its a delimiter - add commas
                  sb.append(", " + chars[i] + ", ");
              } else {
                  // if not - add the char only
                  sb.append(chars[i]);
              }
          }
          System.out.println(sb.toString());
      }
      

      【讨论】:

        【解决方案5】:

        您可以使用基于您的分隔符的正则表达式并破解 appendReplacement/appendTail 来捕获不匹配的字符。这里有解释的代码:

        public class SplitWithDelimiter {
        
          //Do compilation on build, make instance thread-safe !
          private final Pattern pattern;
          public SplitWithDelimiter(String regex) {
            pattern = Pattern.compile(regex);
          }
        
          public List<String> split(String string) {
            List<String> substrings = new ArrayList<>(); // Value to return
        
            Matcher m = pattern.matcher(string);         // Matcher to find delimiters
            StringBuffer buffer = new StringBuffer();    // Buffer to reuse (see hack belows)
        
            while (m.find()) {                           // Find next
        
              m.appendReplacement(buffer, "");           // Hack: Append non-matched characters to the empty buffer
              substrings.add(buffer.toString());         // Adds buffer content
              buffer.delete(0, buffer.length());         // Reset buffer (but keep allocate char array)
        
              substrings.add(m.group());                 // Adds matched delimiter 
            }
        
            m.appendTail(buffer);                        // Hack: Append left characters to the empty buffer
            substrings.add(buffer.toString());           // Adds buffer content
        
            return substrings;
          }
        
          public static void main(String[] args) {
        
            String input = "?cd?34?abef#1256";  // User input
            String chars = "#?";
        
            String regex = "[" + Pattern.quote(chars) + "]";  // Builds a regular expression from char list
            List<String> splits = new SplitWithDelimiter(regex).split(input); // Do the split
            System.out.println(splits);
          }
        }
        

        注意:我假设分隔符序列是独立的。如果不只是从用户输入中适应糟糕的正则表达式生成。我还假设您想要捕获“非匹配字符”的空序列。如果不需要,当buffer 为空时很容易过滤。

        【讨论】:

        • 为以下分隔符而死:#.?*+-[](){}
        • 我没有把重点放在正则表达式的生成上。如前所述,它非常贫穷。我错过了一个“\\”,但它没有按我的预期完成工作(不知道为什么?)。因为它使用Pattern.quote 工作,所以我用它代替!实现正则表达式生成的更简洁的方法。
        【解决方案6】:

        这是一个分隔符,你将它扩展为第二个分隔符

        import java.util.Arrays;
        import java.util.Scanner;
        
        public class StringSplit
        {
            public static void main(String[] args)
            { 
                Scanner scan = new Scanner(System.in);
                System.out.print("Enter a string: ");
                String str = scan.next();
                System.out.print("Specify delimiter(s): ");
                String del = scan.next();
                String[] result = split(str, del);
                System.out.print(Arrays.toString(result));
            }
        
            public static String[] split(String s, String regex)
            {
                String[] myString = s.split(regex);
                int templength = myString.length;
                String[] temp = new String[(2*templength)];
                int y=0;
                for (int i=0;i<templength ;i++) {
        
                    temp[y] = myString[i];
        
                    temp[++y] = regex;
                    y++;
        
                }
               String temp2[]= Arrays.copyOf(temp, temp.length-1);
                return temp2;
            }
        }
        

        【讨论】:

        • 适合以下分隔符:#.?*+-[](){}
        【解决方案7】:

        在你的情况下,正则表达式必须看起来像这样 [?#]

        这就是你的拆分方法的样子

        public static String[] split(String s, String regex)
            {
                String[] myString = s.split("["+regex+"]");
                return myString;
            }
        

        【讨论】:

        • 适用于以下分隔符:#.?*+-[](){}
        • 如果您正在寻找非单词为什么不使用 [\\W],这些是必须转义的元字符,请参阅正则表达式文档docs.oracle.com/javase/tutorial/essential/regex/literals.html
        • 我不是在寻找任何东西,OP 也不是。问题是关于一个用户,他可以输入任何他喜欢的东西作为分隔符。允许使用任何分隔符,甚至是字母和数字以及特殊字符,例如 -]。我只是指出这个答案不支持这一点。
        猜你喜欢
        • 2016-07-25
        • 2020-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-24
        • 2013-11-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多