Регулярное выражение Java для извлечения текста между тегами

82

У меня есть файл с некоторыми настраиваемыми тегами, и я хотел бы написать регулярное выражение для извлечения строки между тегами. Например, если мой тег:

[customtag]String I want to extract[/customtag]

Как мне написать регулярное выражение для извлечения только строки между тегами. Этот код кажется шагом в правильном направлении:

Pattern p = Pattern.compile("[customtag](.+?)[/customtag]");
Matcher m = p.matcher("[customtag]String I want to extract[/customtag]");

Не уверенны что делать дальше. Есть идеи? Благодарю.

b10опасность
источник
1
Во-первых, вам нужно избегать []квадратных скобок, которые являются метасимволами в регулярном выражении.
ridgerunner

Ответы:

186

Вы на правильном пути. Теперь вам просто нужно извлечь нужную группу, как показано ниже:

final Pattern pattern = Pattern.compile("<tag>(.+?)</tag>", Pattern.DOTALL);
final Matcher matcher = pattern.matcher("<tag>String I want to extract</tag>");
matcher.find();
System.out.println(matcher.group(1)); // Prints String I want to extract

Если вы хотите извлечь несколько совпадений, попробуйте следующее:

public static void main(String[] args) {
    final String str = "<tag>apple</tag><b>hello</b><tag>orange</tag><tag>pear</tag>";
    System.out.println(Arrays.toString(getTagValues(str).toArray())); // Prints [apple, orange, pear]
}

private static final Pattern TAG_REGEX = Pattern.compile("<tag>(.+?)</tag>", Pattern.DOTALL);

private static List<String> getTagValues(final String str) {
    final List<String> tagValues = new ArrayList<String>();
    final Matcher matcher = TAG_REGEX.matcher(str);
    while (matcher.find()) {
        tagValues.add(matcher.group(1));
    }
    return tagValues;
}

Однако я согласен с тем, что регулярные выражения здесь не лучший ответ. Я бы использовал XPath для поиска интересующих меня элементов. Для получения дополнительной информации см . Java XPath API .

Hoipolloi
источник
3
Большое спасибо, это именно то, что мне нужно. Я изучу XPath, но пока думаю, что это решение будет работать. Мои приложения очень просты и, вероятно, останутся такими. Еще раз спасибо!
b10hazard
А что насчет этой строки "<tag>apple</tag><b>hello</b><tag>orange</tag><tag>pear"? Как обойтись pearбез закрывающего тега?
K.Sopheak
Для обобщения: private String extractDataFromTags (String tag) {Pattern pattern = Pattern.compile ("<. +?> (. +?) </.+?>"); Матчер matcher = pattern.matcher (tag); matcher.find (); возврат (matcher.group (1)); // Выводит строку, которую я хочу извлечь, или
генерирует
15

Если честно, регулярные выражения - не лучшая идея для такого типа синтаксического анализа. Опубликованное вами регулярное выражение, вероятно, отлично подойдет для простых случаев, но если все станет более сложным, у вас возникнут огромные проблемы (по той же причине, по которой вы не можете надежно анализировать HTML с помощью регулярных выражений). Я знаю, что вы, вероятно, не хотите этого слышать, я знаю, что не слышал, когда задавал вопросы того же типа, но синтаксический анализ строк стал для меня НАМНОГО надежнее после того, как я перестал пытаться использовать регулярные выражения для всего.

jTopas - УДИВИТЕЛЬНЫЙ токенизатор, который позволяет довольно легко писать парсеры вручную (я НАСТОЯТЕЛЬНО предлагаю jtopas вместо стандартных библиотек java-сканера и т. д.). Если вы хотите увидеть jtopas в действии, вот несколько парсеров, которые я написал с помощью jTopas для анализа этого типа файла.

Если вы анализируете файлы XML, вам следует использовать библиотеку парсера xml. Не делайте этого самостоятельно, если только вы не делаете это просто для удовольствия, существует множество проверенных вариантов.

jdc0589
источник
Спасибо за предложение. Я добавил их в закладки, и я обязательно буду использовать их в будущих проектах. На данный момент, вероятно, я буду использовать метод регулярных выражений, поскольку файл, который я анализирую, очень маленький / простой.
b10hazard
7

Общий, более простой и немного примитивный подход к поиску тега, атрибута и значения

    Pattern pattern = Pattern.compile("<(\\w+)( +.+)*>((.*))</\\1>");
    System.out.println(pattern.matcher("<asd> TEST</asd>").find());
    System.out.println(pattern.matcher("<asd TEST</asd>").find());
    System.out.println(pattern.matcher("<asd attr='3'> TEST</asd>").find());
    System.out.println(pattern.matcher("<asd> <x>TEST<x>asd>").find());
    System.out.println("-------");
    Matcher matcher = pattern.matcher("<as x> TEST</as>");
    if (matcher.find()) {
        for (int i = 0; i <= matcher.groupCount(); i++) {
            System.out.println(i + ":" + matcher.group(i));
        }
    }
Горького
источник
Какой будет шаблон, если есть последовательность разных тегов или вложенных тегов, например <h2>Mac</h2><h1>loves it</h1>или <h2>Mac<h1>liked your answer</h1></h2>?
MAC
1
пожалуйста, отредактируйте i <matcher.groupCount (); to i <= matcher.groupCount (); чтобы включить первую совпадающую подстроку, т.е. под индексом 0
AVA
4

Попробуй это:

Pattern p = Pattern.compile(?<=\\<(any_tag)\\>)(\\s*.*\\s*)(?=\\<\\/(any_tag)\\>);
Matcher m = p.matcher(anyString);

Например:

String str = "<TR> <TD>1Q Ene</TD> <TD>3.08%</TD> </TR>";
Pattern p = Pattern.compile("(?<=\\<TD\\>)(\\s*.*\\s*)(?=\\<\\/TD\\>)");
Matcher m = p.matcher(str);
while(m.find()){
   Log.e("Regex"," Regex result: " + m.group())       
}

Вывод:

10 Эне

3,08%

Эриберто Ривера
источник
2
    final Pattern pattern = Pattern.compile("tag\\](.+?)\\[/tag");
    final Matcher matcher = pattern.matcher("[tag]String I want to extract[/tag]");
    matcher.find();
    System.out.println(matcher.group(1));
Бибхути Агарвал
источник
как насчет префикса для тега (если префикс динамический)
user1514499
2
    String s = "<B><G>Test</G></B><C>Test1</C>";

    String pattern ="\\<(.+)\\>([^\\<\\>]+)\\<\\/\\1\\>";

       int count = 0;

        Pattern p = Pattern.compile(pattern);
        Matcher m =  p.matcher(s);
        while(m.find())
        {
            System.out.println(m.group(2));
            count++;
        }
Шубхам Хурана
источник
1

Я ставлю перед этим ответом префикс «вам не следует использовать регулярное выражение для синтаксического анализа XML - это приведет только к крайним случаям, которые не работают должным образом, и к регулярному выражению с постоянно возрастающей сложностью, пока вы пытаетесь его исправить . "

При этом вам нужно продолжить, сопоставив строку и взяв нужную группу:

if (m.matches())
{
   String result = m.group(1);
   // do something with result
}
Ширик
источник