donglu9825 2016-11-28 16:10
浏览 224
已采纳

如何匹配正则表达式直到2个换行符

I'm trying to strip metadata from some news articles I got from Lexis Nexis. I'm currently having some trouble with stripping multiline meta data, that is: my pattern only matches the first line.

I suspect this could be fixed with a negative lookahead that looks for multiple line breaks, but so far I've not been able to work it out.

$article = "SECTION: Media; Blz. 33

LENGTH: 355 woorden

HIGHLIGHT: Verkiezingen Robert Jensen keert vanaf vandaag terug op de
Nederlandse televisie. In 'Jensen kiest voor Amerika' onderzoekt hij de
aantrekkingskracht van Donald Trump. Is hij definitief terug of lonkt misschien
een oude liefde?

Waarom ben je Jensen kiest voor Amerika gaan maken?

,,Ik vind Amerika al mijn hele leven een fascinerend land, ben er vaak en volg
de verkiezingen als fenomeen. Toen Trump maar bleef winnen, begon het idee voor
een tv-programma te leven. Ik wilde alles van die Trump-aanhangers weten want
daar hoor je weinig over.''";

preg_match_all( "/[A-Z\h-]+: *[^]+/", $article, $matches);

var_dump( $matches[0] );
die();

Results in:

array(3) { [0]=> string(23) "SECTION: Media; Blz. 33" [1]=> string(19) "LENGTH: 355 woorden" [2]=> string(70) "HIGHLIGHT: Verkiezingen Robert Jensen keert vanaf vandaag terug op de" } 

As you can only the first line of the highlight data is matched.

I've also put a full article (with multiple examples of multiline metadata) up on regex101.

Edit:

After two answers I realise that my question may not have been totally clear -- sorry about that.

I'm trying to strip/remove the meta data from $article so that only the body of the article is left. In my example I'm using preg_match_all(). Once I can correctly match the meta tags, I'll use preg_replace() to replace it with an empty string. I considered using preg_split(), but than I'd have to guess which of the array items is the actual body -- a meta tag could be longer then the actual body, although that's not a likely scenario.

So what is meta tag? A meta tag always starts with [A-Z\h-]+: and ends with a blank line, i.e. two line breaks.

If you take the aforementioned example and put the tags in an array and the article body in a separate variable it'd look like this:

<?php
$meta_tags = [
"SECTION"   => "Media; Blz. 33",
"LENGTH"    => "355 woorden",
"HIGHLIGHT" => "Verkiezingen Robert Jensen keert vanaf vandaag terug op de
Nederlandse televisie. In 'Jensen kiest voor Amerika' onderzoekt hij de
aantrekkingskracht van Donald Trump. Is hij definitief terug of lonkt misschien
een oude liefde?"
];

$article_body = "Waarom ben je Jensen kiest voor Amerika gaan maken?

,,Ik vind Amerika al mijn hele leven een fascinerend land, ben er vaak en volg
de verkiezingen als fenomeen. Toen Trump maar bleef winnen, begon het idee voor
een tv-programma te leven. Ik wilde alles van die Trump-aanhangers weten want
daar hoor je weinig over.''";

Additional note: There may also be some more meta tags after the body's article, but the preg_replace() on meta tags should also take care of that.

  • 写回答

2条回答 默认 最新

  • douqiang5933 2016-11-28 16:32
    关注

    Since you have no complex matching to do, you could also go with a simple preg_split() that targets the metadata keys as delimiters, and not worry about look-aheads etc.:

    $matches = preg_split( '/\v*([A-Z\h-]+):\h?/', $article, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
    

    Gives you:

    array(6) {
      [0]=> string(7) "SECTION"
      [1]=> string(14) "Media; Blz. 33"
      [2]=> string(6) "LENGTH"
      [3]=> string(11) "355 woorden"
      [4]=> string(9) "HIGHLIGHT"
      [5]=> string(556) "Verkiezingen Robert Jensen keert vanaf vandaag terug op de
    Nederlandse televisie. In 'Jensen kiest voor Amerika' onderzoekt hij de
    aantrekkingskracht van Donald Trump. Is hij definitief terug of lonkt misschien
    een oude liefde?
    
    Waarom ben je Jensen kiest voor Amerika gaan maken?
    /...snip/"
    }
    

    ... which I'm sure you can process onward easily enough, evens are keys and odds are values. ^_^


    But if you do want to use a look-ahead, here's an example:

    preg_match_all('/[A-Z\h-]+:.*?(?=\s*(?:[A-Z\h-]+:|\Z))/s', $article, $matches);
    

    This matches anything that starts with your meta-key, followed by anything that's followed by another meta-key or the end of your data. Better not worry about matching line-breaks here, match what matters instead. The look-ahead could be simplified further to simply (?=[A-Z\h-]+:|\Z), but the \s* trims the trailing space in the values. (And that's why the subsequent actual look-ahead group is specified as ?: non-capture, we don't want to clutter the output now do we.) Result:

    array(3) {
      [0]=> string(23) "SECTION: Media; Blz. 33"
      [1]=> string(19) "LENGTH: 355 woorden"
      [2]=> string(567) "HIGHLIGHT: Verkiezingen Robert Jensen keert vanaf vandaag terug op de
    Nederlandse televisie. In 'Jensen kiest voor Amerika' onderzoekt hij de
    aantrekkingskracht van Donald Trump. Is hij definitief terug of lonkt misschien
    een oude liefde?
    
    Waarom ben je Jensen kiest voor Amerika gaan maken?
    /...snip/"
    }
    

    But if you want to make it nice, rather do this:

    preg_match_all('/([A-Z\h-]+):\h*(.*?)(?=\s*(?:[A-Z\h-]+:|\Z))/s', $article, $matches);
    $parsed = array_combine($matches[1], $matches[2]);
    

    That is, we're adding capture-groups for the key and the value, and then combining them into an associative array. (Do check if you have matches before trying to combine.) Result:

    array(3) {
      ["SECTION"]=> string(14) "Media; Blz. 33"
      ["LENGTH"]=> string(11) "355 woorden"
      ["HIGHLIGHT"]=> string(556) "Verkiezingen Robert Jensen keert vanaf vandaag terug op de
    Nederlandse televisie. In 'Jensen kiest voor Amerika' onderzoekt hij de
    aantrekkingskracht van Donald Trump. Is hij definitief terug of lonkt misschien
    een oude liefde?
    
    Waarom ben je Jensen kiest voor Amerika gaan maken?
    /...snip/"
    }
    

    Edit If all you really want is the body text (now that it's clear where the body text begins: after a one-para highlight meta), and you have no use for the metadata, then just clean up the article with preg_replace matching all sections that start with the meta-key, and match everything 'til the first double (or more) linebreak. (Use \v to match any vertical space.)

    $article = preg_replace('/([A-Z\h-]+):\h*(.*?)[\v]{2,}/s', '', $article);
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 对于相关问题的求解与代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 信号傅里叶变换在matlab上遇到的小问题请求帮助
  • ¥15 保护模式-系统加载-段寄存器
  • ¥15 电脑桌面设定一个区域禁止鼠标操作
  • ¥15 求NPF226060磁芯的详细资料
  • ¥15 使用R语言marginaleffects包进行边际效应图绘制