2017-01-18 37 views
0

我需要拆分包含带标签的部分的字符串。例如:按标签将字符串拆分成不同的变量

String str = "This text is not highlighted <hlTag>but this is</hlTag> this" 
      + " isn't again <hlTag>and this is</hlTag>"; 

的问题是,各部分应(在这个例子中,我只是把它们打印出来)保存到不同的变量,所以我的解析器应该知道,这部分都标记内部,并没有。

我已经有解决方案,它的工作原理,但我使用两个正则表达式在这两种情况下,我认为它可以简化,所以我要求你的帮助做到这一点。

EDITED

我意识到,我的解决方案是错误的 - 我松部分的顺序,我需要它得到尊重。如果突出显示,list.add(new HighlPart(text)),else list.add(new NonHighlPart(text)),我需要解析字符串一次并将零件保存到标记和非标记零件的不同对象中。

有人可以帮我吗?

String preTag = "<hlTag>"; 
String postTag = "</hlTag>"; 

Matcher insideTagsMatcher = Pattern.compile(preTag + "(.+?)" + postTag).matcher(str); 
Matcher outsideTagsMatcher = Pattern.compile("^(.*?)" + preTag + 
    "|" + postTag + "(.*?)" + preTag + 
    "|" + "</hlTag>(.*?)$").matcher(str); 

System.out.println("Highlighted:"); 
while (insideTagsMatcher.find()) { 
    System.out.println(insideTagsMatcher.group(1)); 
} 

System.out.println("\nNot highlighted:"); 
while (outsideTagsMatcher.find()) { 
    for (int i = 1; i <= outsideTagsMatcher.groupCount(); i++) { 
     // each pattern group returns two nulls except of string we need 
     if (outsideTagsMatcher.group(i) != null) 
      System.out.println(outsideTagsMatcher.group(i)); 
    } 
} 

结果是:

 
Highlighted: 
but this is 
and this is 

Not highlighted: 
This text is not highlighted 
this isn't again 
+1

正则表达式是一个糟糕的解析器,除了非常简单的语法。使用一个实际的解析器。 – Andreas

回答

1

一个更清洁,更安全的方法是使用Jsoup

import org.jsoup.Jsoup; 
import org.jsoup.nodes.Document; 
import org.jsoup.nodes.TextNode; 
import java.util.List; 
import java.util.stream.Collectors; 

public class Test { 
public static void main(String[] args) { 
    Document document = Jsoup.parse("This text is not highlighted <hlTag>but this is</hlTag> this isn't again <hlTag>and this is</hlTag>"); 

    List<String> highlighted = document.select("hlTag") 
      .stream() 
      .map(element -> element.html()) 
      .collect(Collectors.toList()); 

    List<String> nonHighlighted = document.body().childNodes().stream() 
      .filter(node -> node instanceof TextNode) 
      .map(node -> node.toString().replaceAll("\n","")) 
      .collect(Collectors.toList()); 

    highlighted.forEach(System.out::println); 
    nonHighlighted.forEach(System.out::println); 
} 
} 

输出:

but this is 
and this is 
This text is not highlighted 
this isn't again 

所讨论的变化后进行更新

List保持插入的元素的顺序。您不能将不同类型的对象添加到列表中。如果我正确理解了您的新需求,您可以执行如下操作:

List<Node> nodes = document.body().childNodes(); 
nodes.forEach(System.out::println); 

节点是一个Node元素列表。每个节点(在该示例中)可以是TextNodeElement类型。在你的例子中,TextNode对应于从body中解析出来时没有包含在标签中的内容,Element对象与标签内容对应。这样,您将拥有一个具有所有元素的唯一列表,并且您可以使用它的对象类型(instanceof)区分它们。

你想打印突出显示的部分?然后:

nodes.stream().filter(node -> node instanceof TextNode).forEach(System.out::println); 

想印刷nonHighlighted部分?然后:

nodes.stream().filter(node -> node instanceof Element).forEach(System.out::println); 
+0

谢谢!还有一个问题 - 可以通过保存部件的顺序将它保存到一个列表中吗?我的意思是,如果我有不同的对象标记和不标记的部分,我可以解析它一次,并做这样的事情 - 如果突出显示,list.add(新的HighlPart(文本)),否则list.add(新的NonHighlPart(文本)) ? –

+0

如果更新了回复,请记住在解决问题时接受回复;) – exoddus