Java 提取标记和属性之间的文本



我正在尝试提取特定标签和属性之间的文本。现在,我尝试提取标签。我正在读取一个".gexf"文件,其中包含XML数据。然后我将这些数据保存为字符串。然后我尝试在"节点"标签之间提取文本。这是我到目前为止的代码:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
private static String filePath = "src/babel.gexf";
public String readFile(String filePath) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(filePath));
try {
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append("n");
line = br.readLine();
}
return sb.toString();
} finally {
br.close();
}
}
public void getNodesContent(String content) throws IOException {
final Pattern pattern = Pattern.compile("<nodes>(\w+)</nodes>", Pattern.MULTILINE);
final Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println(matcher.group(1));
}
}
public static void main(String [] args) throws IOException {
Main m = new Main();
String result = m.readFile(filePath);
m.getNodesContent(result);
}
}

在上面的代码中,我没有得到任何结果。当我尝试使用"我的字符串"等示例字符串时,我得到了结果。gexf 文件的链接(因为它太长了,我不得不上传它): https://files.fm/u/qag5ykrx

我不认为将整个文件内容放入单个字符串中是一个好主意,但我想这将取决于文件中的内容量。如果内容很多,那么我会以不同的方式阅读该内容。很高兴看到文件包含内容的虚构示例。

我想你可以试试这个小方法。它的核心利用正则表达式(RegEx)以及模式/匹配器从标签之间检索所需的子字符串。

使用以下方法阅读文档很重要:

/**
* This method will retrieve a string contained between string tags. You
* specify what the starting and ending tags are within the startTag and
* endTag parameters. It is you who determines what the start and end tags
* are to be which can be any strings.<br><br>
*
* @param inputString (String) Any string to process.<br>
*
* @param startTag (String) The Start Tag String or String. Data content retrieved
* will be directly after this tag.<br><br>
*
* The supplied Start Tag criteria can contain a single special wildcard tag
* (~*~) providing you also place something like the closing chevron (>)
* for an HTML tag after the wildcard tag, for example:<pre>
*
* If we have a string which looks like this:
*      {@code
*      "<p style="padding-left:40px;">Hello</p>"
*      }
*      (Note: to pass double quote marks in a string they must be excaped)
*
* and we want to use this method to extract the word "Hello" from between the
* two HTML tags then your Start Tag can be supplied as "&lt;p~*~&gt;" and of course
* your End Tag can be "&lt;/p&gt;". The "&lt;p~*~&gt;" would be the same as supplying
* "&lt;p style="padding-left:40px;"&gt;". Anything between the characters &lt;p and
* the supplied close chevron (&gt;) is taken into consideration. This allows for
* contents extraction regardless of what HTML attributes are attached to the
* tag. The use of a wildcard tag (~*~) is also allowed in a supplied End
* Tag.</pre><br>
*
* The wildcard is used as a special tag so that strings that actually
* contain asterisks (*) can be processed as regular asterisks.<br>
*
* @param endTag (String) The End Tag or String. Data content retrieval will
* end just before this Tag is reached.<br>
*
* The supplied End Tag criteria can contain a single special wildcard tag
* (~*~) providing you also place something like the closing chevron (&gt;)
* for an HTML tag after the wildcard tag, for example:<pre>
*
* If we have a string which looks like this:
*      {@code
*      "<p style="padding-left:40px;">Hello</p>"
*      }
*      (Note: to pass double quote marks in a string they must be excaped)
*
* and we want to use this method to extract the word "Hello" from between the
* two HTML tags then your Start Tag can be supplied as "&lt;p style="padding-left:40px;"&gt;"
* and your End Tag can be "&lt;/~*~&gt;". The "&lt;/~*~&gt;" would be the same as supplying
* "&lt;/p&gt;". Anything between the characters &lt;/ and the supplied close chevron (&gt;)
* is taken into consideration. This allows for contents extraction regardless of what the
* HTML tag might be. The use of a wildcard tag (~*~) is also allowed in a supplied Start Tag.</pre><br>
*
* The wildcard is used as a special tag so that strings that actually
* contain asterisks (*) can be processed as regular asterisks.<br>
*
* @param trimFoundData (Optional - Boolean - Default is true) By default
* all retrieved data is trimmed of leading and trailing white-spaces. If
* you do not want this then supply false to this optional parameter.
*
* @return (1D String Array) If there is more than one pair of Start and End
* Tags contained within the supplied input String then each set is placed
* into the Array separately.<br>
*
* @throws IllegalArgumentException if any supplied method String argument
* is Null ("").
*/
public static String[] getBetweenTags(String inputString, String startTag,
String endTag, boolean... trimFoundData) {
if (inputString == null || inputString.equals("") || startTag == null ||
startTag.equals("") || endTag == null || endTag.equals("")) {
throw new IllegalArgumentException("ngetBetweenTags() Method Error! - "
+ "A supplied method argument contains Null ("")!n"
+ "Supplied Method Arguments:n"
+ "==========================n"
+ "inputString = "" + inputString + ""n"
+ "startTag = "" + startTag + ""n"
+ "endTag = "" + endTag + ""n");
}
List<String> list = new ArrayList<>();
boolean trimFound = true;
if (trimFoundData.length > 0) {
trimFound = trimFoundData[0];
}
Matcher matcher;
if (startTag.contains("~*~") || endTag.contains("~*~")) {
startTag = startTag.replace("~*~", ".*?");
endTag = endTag.replace("~*~", ".*?");
Pattern pattern = Pattern.compile("(?iu)" + startTag + "(.*?)" + endTag);
matcher = pattern.matcher(inputString);
} else {
String regexString = Pattern.quote(startTag) + "(?s)(.*?)" + Pattern.quote(endTag);
Pattern pattern = Pattern.compile("(?iu)" + regexString);
matcher = pattern.matcher(inputString);
}
while (matcher.find()) {
String match = matcher.group(1);
if (trimFound) {
match = match.trim();
}
list.add(match);
}
return list.toArray(new String[list.size()]);
}

如果没有文件样本,我只能建议这么多。相反,我可以告诉你的是,你可以使用标签搜索循环来获取该文本的子字符串。下面是一个示例:

String s = "<a>test</a><b>list</b><a>class</a>";
int start = 0,  end = 0;
for(int i = 0; i < s.toCharArray().length-1; i++){
if(s.toCharArray()[i] == '<' && s.toCharArray()[i+1] == 'a' &&     s.toCharArray()[i+2] == '>'){
start = i+3;
for(int j = start+3; j < s.toCharArray().length-1; j++){
if(s.toCharArray()[j] == '<' && s.toCharArray()[j+1] == '/' && s.toCharArray()[j+2] == 'a' && s.toCharArray()[j+3] == '>'){
end = j;
System.out.println(s.substring(start, end));
break;
}
}
}
}

上面的代码将搜索字符串 s 中的标签,然后从找到它的地方开始并继续,直到找到结束标签。 然后它使用这两个位置来创建字符串的子字符串,该子字符串是两个标签之间的文本。您可以根据需要堆叠任意数量的这些标签搜索。下面是 2 标签搜索的示例:

String s = "<a>test</a><b>list</b><a>class</a>";
int start = 0,  end = 0;
for(int i = 0; i < s.toCharArray().length-1; i++){
if((s.toCharArray()[i] == '<' && s.toCharArray()[i+1] == 'a' && s.toCharArray()[i+2] == '>') ||
(s.toCharArray()[i] == '<' && s.toCharArray()[i+1] == 'b' && s.toCharArray()[i+2] == '>')){
start = i+3;
for(int j = start+3; j < s.toCharArray().length-1; j++){
if((s.toCharArray()[j] == '<' && s.toCharArray()[j+1] == '/' && s.toCharArray()[j+2] == 'a' && s.toCharArray()[j+3] == '>') || 
(s.toCharArray()[j] == '<' && s.toCharArray()[j+1] == '/' && s.toCharArray()[j+2] == 'b' && s.toCharArray()[j+3] == '>')){
end = j;
System.out.println(s.substring(start, end));
break;
}
}
}
}

唯一的区别是我在 if 语句中添加了子句,以便也获取 b 标签之间的文本。这个系统非常通用,我认为你会为它提供大量的使用。

最新更新