Java在标签和属性之间提取文本

时间:2018-05-05 22:23:49

标签: java regex design-patterns matcher

我正在尝试在特定标签和属性之间提取文本。现在,我试图提取标签。我正在读一个里面有XML数据的“.gexf”文件。然后我将这些数据保存为字符串。然后我试图在“nodes”标签之间提取文本。到目前为止,这是我的代码:

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

2 个答案:

答案 0 :(得分:1)

我不认为将整个文件内容放在一个单独的字符串中是个好主意,但我认为这取决于文件中的内容量。如果它有很多内容,那么我会在内容上略有不同地阅读。很高兴看到文件包含的虚构示例。

我想你可以试试这个小方法。它的核心是使用正则表达式(RegEx)以及 Pattern / Matcher 来从标签之间检索所需的子串。

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

/**
 * 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()]);
}

答案 1 :(得分:0)

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

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标签之间的文本。这个系统非常通用,我认为你将资助它的丰富用途。