2013-08-20 2 views
0

Что регулярное выражение должно быть использовано для извлечения нескольких текстовых блоков, разделенных ихних заголовки, которые также должны быть разобраны, например:Захватив несколько текстовых блоков с регулярным выражением в Java

some text info before message sequence 
============ 
first message header that should be parsed (may contain = character) 
============ 
first multiline 
message body that 
should also be parsed 
(may contain = character) 
============ 
second message header that should be parsed 
============ 
second multiline 
message body that 
should also be parsed 
... and so on 

Я пытался использовать:

String regex = "^=+$\n"+ 
     "^(.+)$\n"+ 
     "^=+$\n"+ 
     "((?s:(?!(^=.+)).+))"; 
Pattern p = Pattern.compile(regex, Pattern.MULTILINE); 

Но ((?s:(?!(^=.+)).+)) ест второе сообщение, как сказка. Это тест, показывающий проблему:

import java.util.regex.Matcher; 
import java.util.regex.Pattern; 
import org.junit.Assert; 
import org.junit.Test; 
public class ParsingTest { 
@Test 
public void test() { 
    String fstMsgHeader = "first message header that should be parsed (may contain = character)"; 
    String fstMsgBody = "first multiline\n"+ 
         "message body that\n"+ 
         "should also be parsed\n"+ 
         "(may contain = character)"; 
    String sndMsgHeader = "second message header that should be parsed"; 
    String sndMsgBody = "second multiline\n"+ 
      "message body that\n"+ 
      "should also be parsed\n"+ 
      "... and so on"; 
    String sample = "some text info before message sequence\n"+ 
        "============\n"+ 
        fstMsgHeader+"\n"+ 
        "============\n"+ 
        fstMsgBody+"\n"+ 
        "============\n"+ 
        sndMsgHeader+"\n"+ 
        "============\n"+ 
        sndMsgBody +"\n"; 
    System.out.println(sample); 
    String regex = "^=+$\n"+ 
        "^(.+)$\n"+ 
        "^=+$\n"+ 
        "((?s:(?!(^=.+)).+))"; 
    Pattern p = Pattern.compile(regex, Pattern.MULTILINE); 
    Matcher matcher = p.matcher(sample); 
    int blockNumber = 1; 
    while (matcher.find()) { 
     System.out.println("Block "+blockNumber+": "+matcher.group(0)+"\n_________________"); 
     if (blockNumber == 1) { 
      Assert.assertEquals(fstMsgHeader, matcher.group(1)); 
      Assert.assertEquals(fstMsgBody, matcher.group(2)); 
     } else { 
      Assert.assertEquals(sndMsgHeader, matcher.group(1)); 
      Assert.assertEquals(sndMsgBody, matcher.group(2)); 
     } 
    } 
} 

}

+4

Почему бы не использовать sample.split ("=============")? – Marc

+1

Какой результат вы ожидаете иметь, и какой из них у вас на самом деле? – sp00m

+0

Рег. split: я закончил с split, но кажется, что захват сообщения и его заголовок с одним регулярным выражением делает код более понятным (один в цикле с групповыми аксессуарами). Поэтому я пытаюсь рассмотреть этот вариант. –

ответ

1

Я не уверен, если это то, что вы ищете, но, возможно, это регулярное выражение поможет

String regex = 
     "={12}\n" + // twelve '=' marks and new line mark 
     "(.+?)" +  // minimal match that has 
     "\n={12}\n" + // new line mark with twelve '=' marks after it 
     "(.+?)(?=\n={12}|$)"; // minimal match that will have new line 
           // character and twelve `=` marks after 
           // it or end of data $ 

и заставить его работать вы должны сделать точку, чтобы также соответствовать новым строковым символам с флагом Pattern.DOTALL.

Pattern p = Pattern.compile(regex, Pattern.DOTALL); 
+0

Pshemo, спасибо, что он работает. Можете ли вы описать, что означает (. +?)? –

+0

@MikhailTsaplin обычно '(. +?)' Жадный, поэтому он попытается найти максимальное возможное. Если вы добавите '?', Это сделает квант '+' неохотой, поэтому он попытается найти минимальное совпадение. Дополнительная информация доступна по адресу http://docs.oracle.com/javase/tutorial/essential/regex/quant.html. – Pshemo

Смежные вопросы