【问题标题】:split string not included a string in java拆分字符串不包括java中的字符串
【发布时间】:2020-10-22 11:04:05
【问题描述】:

如何使用 split-cretiria 拆分以下文本:FIRST、NOW、THEN:

String text = "FIRST i go to the homepage NOW i click on button \"NOW CLICK\" very quick THEN i will become a text result.";

预期是三个句子:

  1. 首先我去主页
  2. 现在我点击按钮“现在点击”非常快
  3. THEN i 将成为文本结果。

此代码不起作用,因为按钮“NOW CLICK”

String[] textArray = text.split("FIRST|NOW|THEN");

【问题讨论】:

  • 除了处理引用的文本,String.split() 会删除作为分割分隔符的匹配文本,所以你永远不会得到FIRST i go to the homepage — 你会得到i go to the homepage

标签: java arrays regex string split


【解决方案1】:

如果我理解正确的话你

  • 想要在关键字FIRST NOW THEN 上分隔文本并将它们保留在结果部分中
  • 但如果这些关键字出现在引号内,则不想拆分它们。

如果我的猜测是正确的而不是split 方法,你可以使用find 来遍历所有

  • 报价
  • 不在引号内的单词,
  • 空格。

这将允许您将所有引号和空格添加到结果中,并且只专注于检查不在引号内的单词,看看您是否应该拆分它们。

表示此类部分的正则表达式可能类似于Pattern.compile("\"[^\"]*\"|\\S+|\\s+");

重要提示:我们需要先搜索“..”,否则 \\S+ 也会匹配 "NOW CLICK" 作为 "NOWCLICK" 作为两个单独的部分,这将防止它被视为单引号。这就是为什么我们要将"[^"]*" 正则表达式(代表引号)放在subregex1|subregex2|subregex3 系列的开头。

这个正则表达式将允许我们迭代文本

FIRST i go to the homepage NOW i click on button "NOW CLICK" very quick THEN i will become a text result.

作为令牌

FIRST i go to the homepage NOW i click on button "NOW CLICK" very quick THEN i will become a text result. THEN i will become a text result.

注意"NOW CLICK" 将被视为单个令牌。因此,即使它 contain 在您要拆分的关键字内,它也永远不会 等于 这样的关键字(因为它将包含其他字符,例如 " ,或者只是引用中的其他词)。这将防止它被视为应该分割文本的 分隔符

使用这个想法,我们可以创建如下代码:

String text = "FIRST i go to the homepage NOW i click on button \"NOW CLICK\" very quick THEN i will become a text result.";
List<String> keywordsToSplitOn = List.of("FIRST", "NOW", "THEN");

//lets search for quotes ".." | words | whitespaces
Pattern p = Pattern.compile("\"[^\"]*\"|\\S+|\\s+");
Matcher m = p.matcher(text);

StringBuilder sb = new StringBuilder();
List<String> result = new ArrayList<>();
while(m.find()){
    String token = m.group();
    if (keywordsToSplitOn.contains(token) && sb.length() != 0){
        result.add(sb.toString());
        sb.delete(0, sb.length());//clear sb
    }
    sb.append(token);
}
if (sb.length() != 0){//include rest of text after last keyword 
    result.add(sb.toString());
}

result.forEach(System.out::println);

输出:

FIRST i go to the homepage 
NOW i click on button "NOW CLICK" very quick 
THEN i will become a text result.

【讨论】:

  • 有趣的是,这是公认的答案,因为它增加了简单问题的复杂性。
  • @JWoodchuck 我不认为主要区别在于“这个解决方案更复杂”,而是它使用与其他答案不同的假设(在我之前发布)。例如,您的解决方案是基于假设 OP 不想在 NOW 上拆分时,它后面跟着 CLICK 而我的是 OP 不想拆分 NOW ,它放在里面引用。对于当前的 OP 示例,我们的解决方案可能会给出相同的结果,但对于 FIRST select option A. NOW CLICK button B. 等其他句子的效果会有所不同。
  • 这是有道理的。猜猜这取决于他们考虑到其他因素(例如复杂性和引入不同(非拆分)方法)的更广泛要求。
  • @JWoodchuck 是的。我假设这可能是XY problem 的另一种情况,其中 OP 想要做某事,但描述仅一个方面/过度简化的情况并显示他的失败尝试(此处使用split)。通常,有问题的尝试对于 OP 来说不是强制性的,即使它是 OP 所询问的内容的一部分。
【解决方案2】:

您需要使用前瞻和后瞻(简单提及here)。

只需将split 方法中的正则表达式更改为以下内容即可:

String[] textArray = text.split("((?=FIRST)|(?=NOW(?! CLICK))|(?=THEN))");

甚至在每个表达式中包含一个空格以防止拆分可能会更好,例如,NOWHERE:

String[] textArray = text.split("((?=FIRST )|(?=NOW (?!CLICK))|(?=THEN ))");

【讨论】:

    【解决方案3】:

    您可以使用模式和匹配器通过组来拆分输入:

    Pattern pattern = Pattern.compile("^(FIRST.*?)(NOW.*?)(THEN.*)$");
    
    String text = "FIRST i go to the homepage NOW i click on button \"NOW CLICK\" very quick THEN i will become a text result.";
    
    Matcher matcher = pattern.matcher(text);
            
    if (matcher.find()) {
        System.out.println(matcher.group(1));
        System.out.println(matcher.group(2));
        System.out.println(matcher.group(3));
    }
    

    输出:

    FIRST i go to the homepage 
    NOW i click on button "NOW CLICK" very quick 
    THEN i will become a text result.
    

    【讨论】:

      【解决方案4】:

      你可以匹配下面的正则表达式。

      /\bFIRST +(?:(?!\bNOW\b)[^\n])+(?<! )|\bNOW +(?:(?!\bTHEN\b)[^\n])+(?<! )|\bTHEN +.*/
      

      Start your engine!

      Java 的正则表达式引擎执行以下操作。

      \bFIRST +      : match 'FIRST' preceded by a word boundary,
                       followed by 1+ spaces
      (?:            : begin a non-capture group
        (?!\bNOW\b)  : use a negative lookahead to assert that
                       the following chars are not 'NOW'  
        [^\n]        : match any char other than a line terminator
      )              : end non-capture group
      +              : execute non-capture group 1+ times
      (?<! )         : use negative lookbehind to assert that the
                       previous char is not a space
      |              : or
      \bNOW +        : match 'NOW' preceded by a word boundary,
                       followed by 1+ spaces
      (?:            : begin a non-capture group
        (?!\bTHEN\b) : use a negative lookahead to assert that
                       the following chars are not 'THEN'  
        [^\n]        : match any char other than a line terminator
      )              : end non-capture group
      +              : execute non-capture group 1+ times
      (?<! )         : use negative lookbehind to assert that the
                       previous char is not a space
      |              : or
      \bTHEN +.*     : match 'THEN' preceded by a word boundary,
                       followed by 1+ spaces then 0+ chars
      

      这使用了一种称为tempered greedy token solution的技术。

      【讨论】:

        【解决方案5】:

        你可以使用这些(Lookahead and Lookbehind):

        public static void main(String args[]) { 
            String text = "FIRST i go to the homepage NOW i click on button \"NOW CLICK\" very quick THEN i will become a text result.";
            String[] textArray = text.split("(?=FIRST)|(?=\\b NOW \\b)|(?=THEN)");
            
            for(String s: textArray) {
                System.out.println(s);
            }
        }
        

        输出:

        FIRST i go to the homepage
         NOW i click on button "NOW CLICK" very quick 
        THEN i will become a text result.
        

        【讨论】:

        • 现在第二个仍然分裂。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-01-26
        • 2014-05-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-08-22
        • 1970-01-01
        相关资源
        最近更新 更多