Регулярний вираз 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]");

Не знаю, що робити далі. Будь-які ідеї? Дякую.


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 для пошуку елементів, які мене цікавлять. Докладніше див. У API Java XPath .


3
Велике спасибі, це саме те, що мені потрібно було. Я розгляну XPaths, але наразі, думаю, це рішення спрацює. Мої програми дуже прості і, ймовірно, залишаться такими. Знову дякую!
b10hazard

Що з цією струною "<tag>apple</tag><b>hello</b><tag>orange</tag><tag>pear"? Як ми можемо отримати pearбез тісного тегу?
K.Sopheak

Узагальнити: private String extractDataFromTags (String tag) {Pattern pattern = Pattern.compile ("<. +?> (. +?) </.+?>"); Збіг збігів = pattern.matcher (тег); matcher.find (); повернення (matcher.group (1)); // Друкує рядок, який я хочу витягти, або
викине

15

Чесно кажучи, регулярні вирази - не найкраща ідея для цього типу розбору. Опублікований вами регулярний вираз, ймовірно, буде чудово працювати для простих випадків, але якщо справа стає більш складною, у вас будуть величезні проблеми (та сама причина, чому ви не можете надійно аналізувати HTML із регулярними виразами). Я знаю, що ви, мабуть, не хочете цього чути, я знаю, що ні, коли я задавав однотипні запитання, але синтаксичний аналіз рядків став для мене НАДІЙ надійнішим після того, як я перестав намагатися використовувати регулярні вирази для всього.

jTopas - це ДИВОВИЙ токенізатор , завдяки якому досить легко писати синтаксичні аналізатори вручну (Я НАСОЛО пропоную jtopas у порівнянні зі стандартними бібліотеками сканера Java та ін.). Якщо ви хочете побачити jtopas в дії, ось кілька синтаксичних аналізаторів, які я написав за допомогою jTopas для синтаксичного аналізу файлів цього типу

Якщо ви розбираєте файли XML, вам слід використовувати бібліотеку синтаксичного аналізатора xml. Не робіть це самостійно, якщо тільки ви не робите це заради задоволення, там є безліч перевірених варіантів


Дякую за пропозицію. Я додав їх у закладки, і, безумовно, буду розглядати можливість використання цього в майбутніх проектах. На даний момент метод регулярного виразу, мабуть, я буду використовувати, оскільки файл, який я розбираю, дуже малий / простий.
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 (); до 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
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.