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 在若依框架下实现人脸识别
  • ¥15 网络科学导论,网络控制
  • ¥100 安卓tv程序连接SQLSERVER2008问题
  • ¥15 利用Sentinel-2和Landsat8做一个水库的长时序NDVI的对比,为什么Snetinel-2计算的结果最小值特别小,而Lansat8就很平均
  • ¥15 metadata提取的PDF元数据,如何转换为一个Excel
  • ¥15 关于arduino编程toCharArray()函数的使用
  • ¥100 vc++混合CEF采用CLR方式编译报错
  • ¥15 coze 的插件输入飞书多维表格 app_token 后一直显示错误,如何解决?
  • ¥15 vite+vue3+plyr播放本地public文件夹下视频无法加载