Написать отрицательную строку в соответствии с POS-тегами - PullRequest
1 голос
/ 12 февраля 2012

Рассмотрим следующую строку с тегом POS:

It/PRP was/VBD not/RB okay/JJ or/CC funny/JJ and/CC I/NN will/MD never/RB buy/VB 
from/IN them/PRP ever/RB again/RB

(It was not okay or funny and I will never buy from them ever again)

Я хочу сделать следующее:

  1. Проверка на отрицание наречий (RB) по отношению к определенному массиву («не», «никогда»)
  2. Когда есть совпадение, уберите наречие
  3. объединяет "не-" с началом каждого последующего прилагательного (JJ), наречий (RB) или глагола (VB или VBN для прошедшего времени)
  4. Удалить все POS-теги (/ XX)

Таким образом, желаемый результат будет:

It was not-okay or not-funny and I will not-buy from them not-ever not-again

Моей первой мыслью было сделать это так, как я знаю: взорвать строку в пространстве, затем взорвать каждое слово в «/» на [JJ => окей], а затем сделать оператор switch для обработки каждого слова JJ: объединение и т. Д.), Но это кажется очень неаккуратным. У кого-нибудь есть более чистый и / или эффективный способ сделать это, например, регулярное выражение? Строки предварительно очищены, поэтому они всегда будут содержать только слова (без знаков препинания, другие символы, кроме a-z и т. Д.).

Редактировать: Между прочим, я осознаю очень простой характер этого способа лечения отрицаний, но он достаточно хорош для того, что мне нужно. Будет ошибка, но это нормально:)

Ответы [ 2 ]

1 голос
/ 13 февраля 2012

Дай мне попробовать.После вашего вопроса об обработке с использованием регулярных выражений,

$s = "It/PRP was/VBD not/RB okay/JJ or/CC funny/JJ and/CC I/NN will/MD 
      never/RB buy/VB from/IN them/PRP ever/RB again/RB";
  1. Проверка на отрицание наречий (RB) в отношении определенного массива ('not', 'never')
  2. Когда естьсовпадение, удалите наречие

    Другими словами, удалите все слова "not" и "never", а затем "/RB".

    $s = preg_replace("/(not|never)\/RB/i", "", $s);
    
  3. Concatenate" not- «к началу каждого последующего прилагательного (JJ), наречий (RB) или глагола (VB или VBN для прошедшего времени)

    $s = preg_replace("/(\w+)\/(JJ|RB|VB|VBN)/", "not-$1/$2", $s);
    
  4. Удалите все POS-теги (/XX)

    При условии, что все POS-теги имеют заглавные буквы

    $s = preg_replace("/\/[A-Z]+/", "", $s);
    
  5. (Мой дополнительный шаг).Удалите все двойные пробелы из результата приведенных выше регулярных выражений.

    $s = preg_replace("/\s+/", " ", $s);
    

Вывод:

It not-was not-okay or not-funny and I will not-buy from them not-ever not-again

Если вы хотите отменить другие POS-теги, отличные отJJ / RB / VB / VBN, просто измените регулярное выражение на шаге 3 (JJ | RB | VB | VBN).Надеюсь, это поможет.

0 голосов
/ 01 сентября 2017

Я бы порекомендовал решение без регулярных выражений, поскольку метод регулярных выражений или без регулярных выражений должен будет выполнять несколько вызовов функций. Если есть способ выполнить эту задачу с помощью простого preg_replace_callback(), я могу только представить, что это будет очень трудно понять на первый взгляд. Мой подход может быть очень похож на ваш оригинальный код (но я не знаю, потому что вы не опубликовали свой).

Метод: ( Демо )

$string='It/PRP was/VBD not/RB okay/JJ or/CC funny/JJ and/CC I/NN will/MD never/RB buy/VB from/IN them/PRP ever/RB again/RB';

$mods=['JJ','RB','VB','VBN'];  // okay to prefix when called for
$omits=['not','never'];  // strings to be omitted every time
$negbool=false;  // states whether a negative adverb has been found
$array=explode(' ',$string);
foreach($array as $k=>&$v){  // make $v modifiable by reference
    $parts=explode('/',$v);
    // add prefix "not-" to strings who qualify
    if($negbool && in_array($parts[1],$mods) && !in_array($parts[0],$omits)){
        $v="not-{$parts[0]}";
    // omit RB strings that don't qualify for prefixing
    }elseif($parts[1]=='RB'){
        unset($array[$k]);  // remove
        $negbool=true;  // declare that modifiable strings should be modified from this point forward
    // keep only leading substring
    }else{
        $v=$parts[0];
    }
}
echo implode(' ',$array); // glue back together again using spaces

Выход:

It was not-okay or not-funny and I will not-buy from them not-ever not-again
...