【问题标题】:How can I split a text into sentences using the Stanford parser?如何使用斯坦福解析器将文本拆分为句子?
【发布时间】:2023-03-15 02:00:02
【问题描述】:

如何使用Stanford parser 将文本或段落拆分成句子?

有没有什么方法可以提取句子,比如getSentencesFromString(),因为它是为Ruby提供的?

【问题讨论】:

  • 我已经下载了解析器包并在上面运行了一个简单的程序,我想对使用解析器从文本中提取句子有一些想法,有什么方法可以用来提取文本中的句子..

标签: java parsing artificial-intelligence nlp stanford-nlp


【解决方案1】:

您可以检查 DocumentPreprocessor 类。下面是一个简短的sn-p。我认为可能还有其他方法可以做你想做的事。

String paragraph = "My 1st sentence. “Does it work for questions?” My third sentence.";
Reader reader = new StringReader(paragraph);
DocumentPreprocessor dp = new DocumentPreprocessor(reader);
List<String> sentenceList = new ArrayList<String>();

for (List<HasWord> sentence : dp) {
   // SentenceUtils not Sentence
   String sentenceString = SentenceUtils.listToString(sentence);
   sentenceList.add(sentenceString);
}

for (String sentence : sentenceList) {
   System.out.println(sentence);
}

【讨论】:

  • 将此代码标记为单词。我正在寻找的是将段落分成句子
  • 我只是这个东西的初学者,如果你不介意,你能提供一个简单的例子吗....
  • 不客气,但请尝试带括号和引号的句子,我认为这是标记化过程的一部分,它用一些符号替换它。
  • 这会在标记之间放置空格。例如。在每个不好的时期之前
  • 我通过使用增强的 for 循环和使用 Sentence 类中的便捷方法将代码列表转换回字符串来简化代码。
【解决方案2】:

我知道已经有一个公认的答案...但通常你只需从带注释的文档中获取 SentenceAnnotations。

// creates a StanfordCoreNLP object, with POS tagging, lemmatization, NER, parsing, and coreference resolution 
Properties props = new Properties();
props.put("annotators", "tokenize, ssplit, pos, lemma, ner, parse, dcoref");
StanfordCoreNLP pipeline = new StanfordCoreNLP(props);

// read some text in the text variable
String text = ... // Add your text here!

// create an empty Annotation just with the given text
Annotation document = new Annotation(text);

// run all Annotators on this text
pipeline.annotate(document);

// these are all the sentences in this document
// a CoreMap is essentially a Map that uses class objects as keys and has values with custom types
List<CoreMap> sentences = document.get(SentencesAnnotation.class);

for(CoreMap sentence: sentences) {
  // traversing the words in the current sentence
  // a CoreLabel is a CoreMap with additional token-specific methods
  for (CoreLabel token: sentence.get(TokensAnnotation.class)) {
    // this is the text of the token
    String word = token.get(TextAnnotation.class);
    // this is the POS tag of the token
    String pos = token.get(PartOfSpeechAnnotation.class);
    // this is the NER label of the token
    String ne = token.get(NamedEntityTagAnnotation.class);       
  }

}

来源 - http://nlp.stanford.edu/software/corenlp.shtml(中途)

如果您只是在寻找句子,您可以从管道初始化中删除后面的步骤,如“parse”和“dcoref”,这将为您节省一些加载和处理时间。摇滚乐。 ~K

【讨论】:

    【解决方案3】:

    接受的答案有几个问题。首先,分词器将一些字符,例如字符“转换为两个字符”。其次,将标记化的文本与空格重新连接在一起不会返回与以前相同的结果。因此,接受答案中的示例文本以非平凡的方式转换输入文本。

    但是,标记器使用的 CoreLabel 类会跟踪它们映射到的源字符,因此如果您有原始字符串,重建正确的字符串是微不足道的。

    下面的方法 1 显示了接受的答案方法,方法 2 显示了我的方法,它克服了这些问题。

    String paragraph = "My 1st sentence. “Does it work for questions?” My third sentence.";
    
    List<String> sentenceList;
    
    /* ** APPROACH 1 (BAD!) ** */
    Reader reader = new StringReader(paragraph);
    DocumentPreprocessor dp = new DocumentPreprocessor(reader);
    sentenceList = new ArrayList<String>();
    for (List<HasWord> sentence : dp) {
        sentenceList.add(Sentence.listToString(sentence));
    }
    System.out.println(StringUtils.join(sentenceList, " _ "));
    
    /* ** APPROACH 2 ** */
    //// Tokenize
    List<CoreLabel> tokens = new ArrayList<CoreLabel>();
    PTBTokenizer<CoreLabel> tokenizer = new PTBTokenizer<CoreLabel>(new StringReader(paragraph), new CoreLabelTokenFactory(), "");
    while (tokenizer.hasNext()) {
        tokens.add(tokenizer.next());
    }
    //// Split sentences from tokens
    List<List<CoreLabel>> sentences = new WordToSentenceProcessor<CoreLabel>().process(tokens);
    //// Join back together
    int end;
    int start = 0;
    sentenceList = new ArrayList<String>();
    for (List<CoreLabel> sentence: sentences) {
        end = sentence.get(sentence.size()-1).endPosition();
        sentenceList.add(paragraph.substring(start, end).trim());
        start = end;
    }
    System.out.println(StringUtils.join(sentenceList, " _ "));
    

    这个输出:

    My 1st sentence . _ `` Does it work for questions ? '' _ My third sentence .
    My 1st sentence. _ “Does it work for questions?” _ My third sentence.
    

    【讨论】:

    • 谢谢,这正是我想要的。希望有一种快速的方法可以从斯坦福 CoreNLP 的服务器或从命令行进行简单的类调用。我不想只为一个用例创建整个 java 项目。知道如何修改它以将文本文件作为输入(而不是将其作为字符串加载?)
    • @Sudhi 我认为如果 CoreNLP 决定将其添加为一个简单的选项,甚至可能是默认选项,那就太好了。修改它以获取文件的最简单方法是将您的阅读器直接传递给 PTBTokenizer 对象(而不是 StringReader),但这会将您的文件读入内存。你需要设计一些东西来在记忆中一次处理一个句子。
    • 实际上,Sentence 类似乎有一个方法Sentence.listToOriginalTextString,它在您的代码中采用List&lt;CoreLabel&gt; sentence 变量。它还提到需要使用"invertible=true" 选项运行 PTBT 标记器。
    • @Sudhi 现在有一个 listToOriginalTextString 方法,但它的操作类似于 Dan 在接受的答案中使用的 listToString 方法。如果您有原始文本(您可能没有),我的方法不需要 -invertible=true 标志并且效率更高(O(2) vs O(n))。
    • @dmn 我同意。我不认为 CoreNLP 决定在标记化后进行句子拆分在大多数现实世界场景中是不现实的,因为您经常希望标记和句子边界要么毫无意义,要么提供不同的信息层。但是,当您只需要句子边界时,处理起来很烦人。
    【解决方案4】:

    使用 .net C# 包: 这将拆分句子,使括号正确并保留原始空格和标点符号:

    public class NlpDemo
    {
        public static readonly TokenizerFactory TokenizerFactory = PTBTokenizer.factory(new CoreLabelTokenFactory(),
                    "normalizeParentheses=false,normalizeOtherBrackets=false,invertible=true");
    
        public void ParseFile(string fileName)
        {
            using (var stream = File.OpenRead(fileName))
            {
                SplitSentences(stream);
            }
        }
    
        public void SplitSentences(Stream stream)
        {            
            var preProcessor = new DocumentPreprocessor(new UTF8Reader(new InputStreamWrapper(stream)));
            preProcessor.setTokenizerFactory(TokenizerFactory);
    
            foreach (java.util.List sentence in preProcessor)
            {
                ProcessSentence(sentence);
            }            
        }
    
        // print the sentence with original spaces and punctuation.
        public void ProcessSentence(java.util.List sentence)
        {
            System.Console.WriteLine(edu.stanford.nlp.util.StringUtils.joinWithOriginalWhiteSpace(sentence));
        }
    }
    

    输入: - 这句话的人物有一定的魅力,在标点符号和散文中很常见。这是第二句?确实如此。

    输出: 3 个句子(“?”被视为句尾分隔符)

    注意:对于像“Havisham 夫人的课程在各个方面都无可挑剔(就人们所见!)”这样的句子。分词器会正确识别出 Mrs. 结尾的句号不是 EOS,但是它会错误地标记 !在括号内作为 EOS 并拆分“在所有方面”。作为第二句话。

    【讨论】:

      【解决方案5】:

      使用 Stanford CoreNLP 3.6.0 或 3.7.0 版本提供的 Simple API

      以下是 3.6.0 的示例。它与 3.7.0 完全相同。

      Java 代码片段

      import java.util.List;
      
      import edu.stanford.nlp.simple.Document;
      import edu.stanford.nlp.simple.Sentence;
      public class TestSplitSentences {
          public static void main(String[] args) {
              Document doc = new Document("The text paragraph. Another sentence. Yet another sentence.");
              List<Sentence> sentences = doc.sentences();
              sentences.stream().forEach(System.out::println);
          }
      }
      

      产量:

      文本段落。

      另一个句子。

      还有一句话。

      pom.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <groupId>stanfordcorenlp</groupId>
          <artifactId>stanfordcorenlp</artifactId>
          <version>1.0-SNAPSHOT</version>
      
          <properties>
              <maven.compiler.source>1.8</maven.compiler.source>
              <maven.compiler.target>1.8</maven.compiler.target>
          </properties>
      
          <dependencies>
              <!-- https://mvnrepository.com/artifact/edu.stanford.nlp/stanford-corenlp -->
              <dependency>
                  <groupId>edu.stanford.nlp</groupId>
                  <artifactId>stanford-corenlp</artifactId>
                  <version>3.6.0</version>
              </dependency>
              <!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java -->
              <dependency>
                  <groupId>com.google.protobuf</groupId>
                  <artifactId>protobuf-java</artifactId>
                  <version>2.6.1</version>
              </dependency>
          </dependencies>
      </project>
      

      【讨论】:

      • 你在开玩笑吗?抱歉,但我必须复制它以查看它是否属实
      • 是的,不幸的是,它不起作用:) 我导入了 maven 3.6.0 版
      【解决方案6】:

      您可以使用document preprocessor。这真的很容易。只需给它一个文件名。

          for (List<HasWord> sentence : new DocumentPreprocessor(pathto/filename.txt)) {
               //sentence is a list of words in a sentence
          }
      

      【讨论】:

        【解决方案7】:

        你可以很容易地使用斯坦福标记器。

        String text = new String("Your text....");  //Your own text.
        List<List<HasWord>> tokenizedSentences = MaxentTagger.tokenizeText(new StringReader(text));
        
        for(List<CoreLabel> act : tokenizedSentences)       //Travel trough sentences
        {
            System.out.println(edu.stanford.nlp.ling.Sentence.listToString(act)); //This is your sentence
        }
        

        【讨论】:

          【解决方案8】:

          @Kevin 答案的一个变体将解决这个问题,如下所示:

          for(CoreMap sentence: sentences) {
                String sentenceText = sentence.get(TextAnnotation.class)
          }
          

          它可以在不打扰其他注释器的情况下为您获取句子信息。

          【讨论】:

            【解决方案9】:

            除了一些被否决的答案外,另一个没有解决的元素是如何设置句子分隔符?默认情况下,最常见的方法是依赖于表示句子结尾的常见标点符号。从收集的语料库中提取可能会面临其他文档格式,其中一种是每一行都是它自己的句子。

            要按照接受的答案设置 DocumentPreprocessor 的分隔符,您可以使用 setSentenceDelimiter(String)。要使用@Kevin 回答中建议的管道方法,可以使用 ssplit 属性。例如,要使用上一段中提出的行尾方案,可以将属性ssplit.eolonly 设置为true

            【讨论】:

              【解决方案10】:

              在下面的代码中添加输入和输出文件的路径:-

              import java.util.*;
              import edu.stanford.nlp.pipeline.*;
              import java.io.BufferedReader;
              import java.io.BufferedWriter;
              import java.io.FileReader;
              import java.io.FileWriter;
              import java.io.IOException;
              import java.io.PrintWriter;
              public class NLPExample
              {
                  public static void main(String[] args) throws IOException 
                  {
                      PrintWriter out;
                      out = new PrintWriter("C:\\Users\\ACER\\Downloads\\stanford-corenlp-full-     
                      2018-02-27\\output.txt");
                      Properties props=new Properties();
                      props.setProperty("annotators","tokenize, ssplit, pos,lemma");
                      StanfordCoreNLP pipeline = new StanfordCoreNLP(props);
                      Annotation annotation;  
                      String readString = null;
                      PrintWriter pw = null;
                      BufferedReader br = null;
                      br = new BufferedReader (new 
                      FileReader("C:\\Users\\ACER\\Downloads\\stanford- 
                      corenlp-full-2018-02-27\\input.txt" )  ) ;
                      pw = new PrintWriter ( new BufferedWriter ( new FileWriter ( 
                      "C:\\Users\\ACER\\Downloads\\stanford-corenlp-full-2018-02-   
                      27\\output.txt",false 
                      ))) ;      
                      String x = null;
                      while  (( readString = br.readLine ())  != null)
                      {
                          pw.println ( readString ) ; String 
                          xx=readString;x=xx;//System.out.println("OKKKKK"); 
                          annotation = new Annotation(x);
                          pipeline.annotate(annotation);    //System.out.println("LamoohAKA");
                          pipeline.prettyPrint(annotation, out);
                      }
                      br.close (  ) ;
                      pw.close (  ) ;
                      System.out.println("Done...");
                  }    
              }
              

              【讨论】:

                【解决方案11】:
                public class k {
                
                public static void main(String a[]){
                
                    String str = "This program splits a string based on space";
                    String[] words = str.split(" ");
                    for(String s:words){
                        System.out.println(s);
                    }
                    str = "This     program  splits a string based on space";
                    words = str.split("\\s+");
                }
                }
                

                【讨论】:

                  【解决方案12】:

                  使用正则表达式将文本拆分成句子, 在使用正则表达式,但在 java 中我不知道。

                  代码

                  string[] 句子 = Regex.Split(text, @"(?

                  90% 有效

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2013-05-07
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多