Как извлечь именные словосочетания из проанализированного текста

Я проанализировал текст с помощью синтаксического анализатора округа, скопировав результат в текстовый файл, как показано ниже:

(ROOT (S (NP (NN Yesterday)) (, ,) (NP (PRP we)) (VP (VBD went) (PP (TO to)....
(ROOT (FRAG (SBAR (SBAR (IN While) (S (NP (PRP I)) (VP (VBD was) (NP (NP (EX...
(ROOT (S (NP (NN Yesterday)) (, ,) (NP (PRP I)) (VP (VBD went) (PP (TO to.....
(ROOT (FRAG (SBAR (SBAR (IN While) (S (NP (NNP Jim)) (VP (VBD was) (NP (NP (....
(ROOT (S (S (NP (PRP I)) (VP (VBD started) (S (VP (VBG talking) (PP.....

Мне нужно извлечь все NounPhrases (NP) из этого текстового файла. Я написал следующий код, который извлекает только первый NP из каждой строки. Однако мне нужно извлечь все словосочетания с существительными. Мой код:

public class nounPhrase {

    public static int findClosingParen(char[] text, int openPos) {
        int closePos = openPos;
        int counter = 1;
        while (counter > 0) {
            char c = text[++closePos];
            if (c == '(') {

                counter++;
            }
            else if (c == ')') {
                counter--;
            }
        }
        return closePos;
    }

     public static void main(String[] args) throws IOException {

        ArrayList npList = new ArrayList ();
        String line;
        String line1;
        int np;

        String Input = "/local/Input/Temp/Temp.txt";

        String Output = "/local/Output/Temp/Temp-out.txt";  

        FileInputStream  fis = new FileInputStream (Input);
        BufferedReader br = new BufferedReader(new InputStreamReader(fis,"UTF-8"
        ));
        while ((line = br.readLine())!= null){
        char[] lineArray = line.toCharArray();
        np = findClosingParen (lineArray, line.indexOf("(NP"));
        line1 = line.substring(line.indexOf("(NP"),np+1);
        System.out.print(line1+"\n");
        }
    }
}

Результат:

(NP (NN Yesterday))...I need other NPs in this line also
(NP (PRP I)).....I need other NPs in this line also
(NP (NNP Jim)).....I need other NPs in this line also
(NP (PRP I)).....I need other NPs in this line also

Мой код принимает только первый NP в каждой строке с закрывающей скобкой, но мне нужно извлечь все NP из текста.


person user3147590    schedule 21.03.2015    source источник
comment
Когда вы копируете код (без вкладок), выберите весь блок и нажмите Ctrl + K, чтобы сделать отступ всего этого на 4 пробела, необходимых для разметки блока кода (таким образом, последняя фигурная скобка также будет включена. Спасибо). никогда не должен быть частью хорошего вопроса. Не вежливо пропустить это, но это будет пустой тратой времени читателей, когда вы его вставите.   -  person Anthon    schedule 21.03.2015


Ответы (4)


Хотя написание собственного синтаксического анализатора дерева является хорошим упражнением (!), но если вы просто хотите получить результаты, самый простой способ — использовать дополнительные функциональные возможности Стэнфордских инструментов НЛП, а именно Tregex, который предназначен именно для таких вещей. Вы можете изменить свой последний цикл while примерно так:

TregexPattern tPattern = TregexPattern.compile("NP");
while ((line = br.readLine()) != null) {
    Tree t = Tree.valueOf(line);
    TregexMatcher tMatcher = tPattern.matcher(t);
    while (tMatcher.find()) {
      System.out.println(tMatcher.getMatch());
    }
}
person Christopher Manning    schedule 22.03.2015

Ну вот. Я немного изменил его, и он стал беспорядочным, но я могу его почистить, если вам действительно нужен красивый код.

import java.io.*;
import java.util.*;

public class nounPhrase {
    public static void main(String[] args)throws IOException{

        ArrayList<String> npList = new ArrayList<String>();
        String line = "";
        String line1 = "";

        String Input = "/local/Input/Temp/Temp.txt";
        String Output = "/local/Output/Temp/Temp-out.txt";

        FileInputStream  fis = new FileInputStream (Input);
        BufferedReader br = new BufferedReader(new InputStreamReader(fis,"UTF-8"));

        while ((line = br.readLine()) != null){
            char[] lineArray = line.toCharArray();
            int temp;
            for (int i=0; i+2<lineArray.length; i++){
                if(lineArray[i]=='(' && lineArray[i+1]=='N' && lineArray[i+2]=='P'){
                    temp = i;
                    while(lineArray[i] != ')'){
                        i++;
                    }
                    i+=2;
                    line1 = line.substring(temp,i);
                    npList.add(line1);
                }
            }
            npList.add("*");
        }

        for (int i=0; i<npList.size(); i++){
            if(!(npList.get(i).equals("*"))){
                System.out.print(npList.get(i));
                if(i<npList.size()-1 && npList.get(i+1).equals("*")){
                    System.out.println();
                }
            }
        }
    }
} 

и, к вашему сведению, основная причина, по которой ваш код выбрал только первое вхождение NP, заключается в том, что вы использовали метод indexOf для поиска местоположения. IndexOf ВСЕГДА и ТОЛЬКО принимает первое вхождение строки, которую вы ищете.

person Benjamin Winters    schedule 21.03.2015

Вы должны выполнить итерацию по дереву синтаксического анализа и изменить индекс для фразы существительного после получения первой фразы NP, простым подходом может быть просто подстрока вашей линейной переменной, и начальный индекс этой подстроки будет np+1. Ниже приведены изменения, которые вы можете внести в свой код:

while ((line = br.readLine())!= null){
        char[] lineArray = line.toCharArray();
        int indexOfNP = line.indexOf("(NP");
        while(indexOfNP!=-1) {
            np = findClosingParen(lineArray, indexOfNP);
            line1 = line.substring(indexOfNP, np + 1);
            System.out.print(line1 + "\n");
            npList.add(line1);
            line = line.substring(np+1);
            indexOfNP = line.indexOf("(NP");
            lineArray = line.toCharArray();
        }
}

Для рекурсивного решения:

public static void main(String[] args) throws IOException {

    ArrayList<String> npList = new ArrayList<String>();
    String line;
    String Input = "/local/Input/Temp/Temp.txt";
    String Output = "/local/Output/Temp/Temp-out.txt";

    FileInputStream fis = new FileInputStream (Input);
    BufferedReader br = new BufferedReader(new InputStreamReader(fis,"UTF-8"));
    while ((line = br.readLine())!= null){
        int indexOfNP = line.indexOf("(NP");
        if(indexOfNP>=0)
            extractNPs(npList,line,indexOfNP);
    }

    for(String npString:npList){
        System.out.println(npString);
    }

    br.close();
    fis.close();

}

public static ArrayList<String> extractNPs(ArrayList<String> arr,String  
                                                   parse, int indexOfNP){
    if(indexOfNP==-1){
        return arr;
    }
    else{
        int npIndex = findClosingParen(parse.toCharArray(), indexOfNP);
        String mainNP = new String(parse.substring(indexOfNP, npIndex + 1));
        arr.add(mainNP);
        //Uncomment Lines below if you also want MainNP along with all NPs     
        //within MainNP to be extracted
        /*
        mainNP = new String(mainNP.substring(3));
        if(mainNP.indexOf("(NP")>0){
            return extractNPs(arr,mainNP,mainNP.indexOf("(NP"));
        }
        */
        parse = new String(parse.substring(npIndex+1));
        indexOfNP = parse.indexOf("(NP");
        return extractNPs(arr,parse,indexOfNP);
    }
}
person Shahid Siddiq    schedule 21.03.2015

Вы создаете синтаксический анализатор (.. для кода, сгенерированного вашим синтаксическим анализатором естественного языка), который является предметом обширной академической документации. Самый простой синтаксический анализатор, который вы можете построить, — это синтаксический анализатор LL. Взгляните на эту статью из Википедии, в которой есть несколько довольно хороших примеров для вдохновения: http://en.wikipedia.org/wiki/LL_parser

Запись в Википедии о синтаксическом анализе в целом может дать вам представление об области синтаксического анализа в целом: Статья в Википедии: http://en.wikipedia.org/wiki/Parsing

person Jules G.M.    schedule 21.03.2015
comment
Моя проблема не в парсере, а в обработке текста. Я уже проанализировал текст, и теперь мне нужно извлечь все шаблоны NP. - person user3147590; 21.03.2015
comment
да. я говорю, что то, что вы на самом деле пытаетесь сделать, это анализировать вывод синтаксического анализатора NP. - person Jules G.M.; 21.03.2015