如何从文本中提取引用(PHP)?

3

你好!

我想从文本中提取所有引用,此外还应提取被引用人的姓名。DayLife做得非常好。

示例:

“他们认为‘游戏结束了’,”一位高级行政官员说。

应提取短语他们认为“游戏结束了”和被引用人一位高级行政官员

你觉得这可能吗?只有在检查是否提到被引用人时,才能区分引用和引号中的单词。

示例:

“我认为情况严重,正在恶化,”穆伦上将周日在CNN的“国情咨文”节目上说。

短语国情咨文不是引语。但是如何检测?a) 检查是否提到了被引用的人。 b) 计算所谓引语中的空格数。如果空格少于3个,则不会是引语,对吗? 我更喜欢b),因为并不总是有被引用的人。

如何开始?

我首先会将所有引号替换为单一类型,以便稍后只需检查一个引号标记。

<?php
$text = '';
$quote_marks = array('“', '”', '„', '»', '«');
$text = str_replace($quote_marks, '"', $text);
?>

然后,我会提取所有包含超过3个空格的引号之间的短语:

<?php
function extract_quotations($text) {
   $result = preg_match_all('/"([^"]+)"/', $text, $found_quotations);
   if ($result == TRUE) {
      return $found_quotations;
      // check for count of blank spaces
   }
   return array();
}
?>

你如何改进这个问题?

希望你能帮我。非常感谢!


也许 $text = preg_replace('/([“”"'»«])(.+?)\1/', '"\2"', $text); 给我们一个输入和期望的输出示例。 - Havenard
3
这种自然语言解析不太可能适应一个简单的函数。如果想要得到良好的结果,它很快就会变得非常复杂。 - ceejayoz
@Havenard:例子已经在问题中了。;) 请看“例子”段落。你的代码应该做什么?我不明白。 - caw
3个回答

4
正如ceejayoz所指出的那样,这无法适合单个函数。您在问题中描述的内容(检测句子中引用部分的语法功能-例如,“我认为它很严重并且正在恶化”,与“联合国大会”)最好使用可以将自然语言分解为标记的库来解决。我不知道PHP中是否有这样的库,但是您可以查看在Python中使用的一些项目的大小:http://www.nltk.org/ 我认为您能做的最好的事情就是定义一组手动验证的语法规则。像这样的东西怎么样:
abstract class QuotationExtractor {

    protected static $instances;

    public static function getAllPossibleQuotations($string) {
        $possibleQuotations = array();
        foreach (self::$instances as $instance) {
            $possibleQuotations = array_merge(
                $possibleQuotations,
                $instance->extractQuotations($string)
            );
        }
        return $possibleQuotations;
    }

    public function __construct() {
        self::$instances[] = $this;
    }

    public abstract function extractQuotations($string);

}

class RegexExtractor extends QuotationExtractor {

    protected $rules;

    public function extractQuotations($string) {
        $quotes = array();
        foreach ($this->rules as $rule) {
            preg_match_all($rule[0], $string, $matches, PREG_SET_ORDER);
            foreach ($matches as $match) {
                $quotes[] = array(
                    'quote' => trim($match[$rule[1]]),
                    'cited' => trim($match[$rule[2]])
                );
            }
        }
        return $quotes;
    }

    public function addRule($regex, $quoteIndex, $authorIndex) {
        $this->rules[] = array($regex, $quoteIndex, $authorIndex);
    }

}

$regexExtractor = new RegexExtractor();
$regexExtractor->addRule('/"(.*?)[,.]?\h*"\h*said\h*(.*?)\./', 1, 2);
$regexExtractor->addRule('/"(.*?)\h*"(.*)said/', 1, 2);
$regexExtractor->addRule('/\.\h*(.*)(once)?\h*said[\-]*"(.*?)"/', 3, 1);

class AnotherExtractor extends Quot...

如果您有像上面这样的结构,可以将相同的文本运行到任意/所有中,并列出可能的引用以选择正确的引用。我已经使用此线程作为输入进行了测试,结果如下:
array(4) {
  [0]=>
  array(2) {
    ["quote"]=>
    string(15) "Not necessarily"
    ["cited"]=>
    string(8) "ceejayoz"
  }
  [1]=>
  array(2) {
    ["quote"]=>
    string(28) "They think it's `game over,'"
    ["cited"]=>
    string(34) "one senior administration official"
  }
  [2]=>
  array(2) {
    ["quote"]=>
    string(46) "I think it is serious and it is deteriorating,"
    ["cited"]=>
    string(14) "Admiral Mullen"
  }
  [3]=>
  array(2) {
    ["quote"]=>
    string(16) "Not necessarily,"
    ["cited"]=>
    string(0) ""
  }
}

不,它是用PHP编写的。我添加了nltk的参考来展示正确处理它的复杂性。 - soulmerge
太好了! :) 那么我可能可以使用它。我如何向函数提供输入?我如何调用该函数?还有:我是否可以在addRule部分中简单地添加我的正则表达式以查找引用? - caw
您可以复制粘贴代码,并使用addRule()添加自己的正则表达式。但是,如果您不打算添加比正则表达式更复杂的提取算法,那么您可以直接使用代码中的3个正则表达式和preg_match_all()。其余部分是一个很好的OO-API,允许您创建其他提取器 - 比如做一些解析的提取器。 - soulmerge
非常感谢!现在我明白了。我会在这里另外一个问题中寻求“完美的正则表达式”。 :) - caw

3
如果少于3个空格,它就不会是一个引用,对吗? "不一定," ceejayoz说。如何检测“国情咨文”这一段不是引用呢? a)检查是否提到了引用的人物;b)计算所谓引文中的空格数。如果少于3个空格,它就不是引用,对吗?我更喜欢b),因为并不总是有一个被引用的人名。但b)甚至都不能用于这个例子-“国情咨文”中有3个空格。

“不一定。”哦,是的,当然,你说得对。:) 但通常情况下不会只有一个。如果只有一个,那么通常它也不会很重要,对吧?b)可以增加到4!? - caw
@marco92w和“#LK$#@^”通常不会在内存中找到,那么为什么不使用它们来分隔缓存中的块呢? - Lucas Oman
我知道会有一些例外情况。但是我不需要找到全部引用。如果我能找到90%的引用,我会很高兴。 - caw

0

引用总是有标点符号——要么是在结尾处加上逗号,表示说话者的姓名或头衔将随之而来,要么是句子的结尾(.!?)。


许多非引语也会这样。"总统向国会发表的年度演讲被称为“国情咨文”。" - ceejayoz
1
@ceejayoz:你引用的字符串没有以标点符号结尾。包含它的句子已经有了。引用将在引号内部具有标点符号。 - Lucas Oman
是的,我认为这可以帮助找到报价。 - caw
1
@Lucas Oman - 在美国是这样的。在英国皇家英语中,如果标点符号不适用于引语,则只有在逻辑上有意义时才将其放在引号内。否则,它应该放在外面。 - ceejayoz
很遗憾,这也不适用于其他语言。但是标点符号只是其中的一部分。您可以轻松地为每种语言实现标点符号分析。 - caw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接