2009-05-13 26 views
22

Làm thế nào để bạn có đoạn văn bản hoặc số lượng lớn văn bản và chia thành các câu (tốt hơn là sử dụng Ruby) có tính đến các trường hợp như ông và Tiến sĩ và Hoa Kỳ? (Giả sử bạn chỉ cần đặt các câu vào một mảng các mảng)Làm cách nào để phân tích cú pháp một đoạn văn bản thành các câu? (perferrably trong Ruby)

CẬP NHẬT: Một giải pháp có thể tôi nghĩ đến bao gồm việc sử dụng trình gắn thẻ từng phần (POST) và trình phân loại để xác định kết thúc câu:

Lấy dữ liệu từ ông Jones cảm thấy mặt trời ấm áp trên khuôn mặt của mình khi ông bước ra ngoài ban công của ngôi nhà mùa hè của mình ở Ý. Anh vui mừng được sống.

CLASSIFIER Mr./PERSON Jones/PERSON cảm thấy/O/O ấm/O mặt trời/O trên/O mặt/O/O/O/O ra/O lên/O/O ban công/O/O của anh/O mùa hè/O nhà/O trong/O Ý/VỊ TRÍ/Anh/O là/O hạnh phúc/O đến/O được/O còn sống/O. /O

POST Mr./NNP Jones/NNP cảm thấy/VBD/DT ấm/JJ mặt trời/NN trên/IN/PRP $ khuôn mặt/NN của mình như/IN/PRP bước/VBD ra/RP lên/IN/DT ban/NN của/IN/PRP $ mùa hè/NN home/NN in/IN Italy./NNP Anh/PRP/VBD hạnh phúc/JJ đến/TO/VB còn sống./IN

Chúng ta có thể giả định, vì Ý là một địa điểm, giai đoạn này là kết thúc hợp lệ của câu? Kể từ khi kết thúc vào "Mr." sẽ không có phần nào khác của bài phát biểu, chúng ta có thể giả định đây không phải là một giai đoạn kết thúc hợp lệ không? Đây có phải là câu trả lời hay nhất cho câu hỏi của tôi không?

Suy nghĩ?

+0

Có bất kỳ quy tắc cụ thể.Nếu bạn có thể cho chúng tôi biết các quy tắc bằng tiếng Anh, tôi chắc chắn chúng tôi (hoặc bạn) sẽ có thể viết mã giải pháp. Ví dụ: các từ viết tắt như 'abbr' có một điểm dừng đầy đủ sau chúng không? Nếu bạn định phân tích sách giáo khoa ngữ pháp, bạn có thể ổn với các giải pháp đơn giản, nhưng nếu bạn đang dùng văn bản tùy ý thì mọi giải pháp sẽ có những thiếu sót, như ... bạn biết không? – Marcin

+0

Trình gắn thẻ POS quá mức cần thiết. Sử dụng trình mã hóa dựa trên NLP và các quy tắc của bạn sẽ đơn giản hơn. –

Trả lời

13

Hãy thử xem Ruby wrapper around the Stanford Parser. Nó có hàm getSentencesFromString().

+0

Tôi sẽ tiếp tục phát với trình phân tích cú pháp Stanford - ở đó đâu đó! Cảm ơn! – henry74

+2

edu.stanford.nlp.process.DocumentPreprocessor, bằng cách này – Stompchicken

+4

Có, hoặc thông qua trình bao bọc của Ruby hoặc trực tiếp bằng cách gọi edu.stanford.nlp.process.DocumentPreprocessor (từ mã hoặc từ dòng lệnh: java edu.stanford .nlp.process.DocumentPreprocessor /u/nlp/data/lexparser/textDocument.txt> oneTokenizedSentencePerLine.txt, bạn có thể chia văn bản thành câu (Điều này được thực hiện thông qua một FSM (tốt nhưng heuristic), vì vậy nó nhanh chóng; bạn ' không phải chạy trình phân tích cú pháp xác suất.) –

0

Tôi không phải là một chàng trai Ruby, nhưng một RegEx rằng chia trên

^(Mr|Mrs|Ms|Mme|Sta|Sr|Sra|Dr|U\.S\.A)[\.\!\?\"] [A-Z] 

sẽ là lựa chọn tốt nhất của tôi, một khi bạn đã có đoạn (split trên \ r \ n). Điều này giả định rằng các câu của bạn là phù hợp.

Rõ ràng đây là một RegEx khá xấu xí. Điều gì về việc buộc hai dấu cách giữa các câu

1

Có thể thử chia nhỏ khoảng trắng theo một khoảng thời gian theo sau là một chữ cái viết hoa? Tôi không chắc chắn làm thế nào để tìm chữ hoa, nhưng đó sẽ là mô hình tôi muốn bắt đầu xem xét.

Edit:Finding uppercase letters with Ruby.

Một Edit:

Kiểm tra cho câu kết thúc chấm câu mà làm theo những lời mà không bắt đầu với chữ hoa.

+2

Xin chào, Mr. Jarrod. Tôi không nghĩ rằng nó sẽ làm việc. –

+0

Điều gì sẽ xảy ra nếu bạn chia nhỏ các giai đoạn theo sau các từ không bắt đầu bằng chữ in hoa? – Jarrod

+0

Đây chính xác là những gì tôi nghĩ ra, nhưng tôi muốn biết liệu có giải pháp nào tốt hơn hay không. Cấp nó sẽ không hoạt động nếu câu kết thúc với một danh từ thích hợp như "Tôi đã đi đến Ý." – henry74

0

Breaking trên một khoảng thời gian theo sau là một không gian và một chữ cái viết hoa sẽ không bay cho các chức danh như "Mr. Brown."

Khoảng thời gian khiến mọi thứ trở nên khó khăn, nhưng một trường hợp dễ xử lý là dấu chấm than và dấu chấm hỏi. Tuy nhiên, có những trường hợp sẽ làm cho điều này không hoạt động. tức là tên công ty của Yahoo!

0

Vâng rõ ràng paragraph.split('.') sẽ không cắt nó

#split sẽ mất một regex như một câu trả lời, do đó bạn có thể thử sử dụng một lookbehind zero-width để kiểm tra một từ bắt đầu với một chữ cái viết hoa.Tất nhiên điều này sẽ chia nhỏ trên danh từ thích hợp, do đó bạn có thể phải nghỉ mát đến một regex như thế này /(Mr\.|Mrs\.|U\.S\.A ...) mà sẽ horrendously xấu xí, trừ khi bạn xây dựng các regex lập trình.

0

Tôi nghĩ điều này không phải lúc nào cũng có thể giải quyết được, nhưng bạn có thể chia nhỏ dựa trên "." (Khoảng thời gian tiếp theo và không gian trống) và xác minh rằng từ trước thời kỳ không có trong danh sách các từ như Mr, Dr , v.v.

Nhưng, tất nhiên, danh sách của bạn có thể bỏ qua một số từ và trong trường hợp đó, bạn sẽ nhận được kết quả không tốt.

8

Để làm rõ, không có giải pháp đơn giản nào cho điều đó. Đây là chủ đề của nghiên cứu NLP như một chương trình quick Google search.

Tuy nhiên, có vẻ như rằng có một số dự án nguồn mở đối phó với NLP hỗ trợ phát hiện bản án, tôi thấy sau bộ công cụ dựa trên nền Java:

openNLP

bình luận bổ sung: Các vấn đề quyết định câu bắt đầu và kết thúc ở đâu cũng được gọi là sentence boundary disambiguation (SBD) trong natural language processing.

+0

Tôi đã không thể tìm thấy một wrapper ruby ​​dễ dàng cho openNLP - bạn có gặp bất kỳ cái gì không? Họ đã có một splitter câu mặc dù ... – henry74

+0

@phillc: Vâng, được gọi là câu ranh giới định hướng "là vấn đề trong xử lý ngôn ngữ tự nhiên của quyết định nơi câu bắt đầu và kết thúc". (http://en.wikipedia.org/wiki/Sentence_boundary_disambiguation) –

4

Đây là một vấn đề khó nếu bạn thực sự quan tâm đến việc làm đúng. Bạn sẽ thấy rằng các gói phân tích cú pháp NLP có thể cung cấp chức năng này. Nếu bạn muốn một cái gì đó nhanh hơn, bạn sẽ cần phải sao chép một số chức năng đó với chức năng xác thực được huấn luyện của một cửa sổ mã thông báo (bạn có thể muốn đếm một dòng cấp dưới dạng mã thông báo, vì tôi có thể mất một khoảng thời gian nếu đó là kết thúc của một đoạn).

Chỉnh sửa: Tôi khuyên bạn nên sử dụng trình phân tích cú pháp Stanford nếu bạn có thể sử dụng Java. Tôi không có đề xuất nào cho các ngôn ngữ khác, nhưng tôi rất thích nghe những điều khác ngoài đó là nguồn mở.

+0

Có, tôi đã chơi với trình phân tích cú pháp NLP của Stanford nhưng không tìm thấy bộ tách câu. Nếu bạn quan tâm đến việc sử dụng nó, có một rjb (ruby để java cầu) wrapper ai đó tạo ra trên github mà tôi đã có thể làm việc một cách tương đối dễ dàng. Đây là liên kết cho những người bạn quan tâm http://github.com/tiendung/ruby-nlp/tree/master LƯU Ý: trên cửa sổ, bạn phải thay đổi dấu hai chấm thành dấu hai chấm khi tải thư viện java. Chúc mừng. – henry74

+0

Bạn nói đúng, không có trình phân tách câu trong gói trình phân tích cú pháp, nhưng có một mã thông báo giúp bạn trở thành một phần của cách thức đó. Nó xử lý những thứ như những người đã đề cập, "Ông" dưới dạng mã thông báo so với "." như là một kết thúc của câu. –

+2

Có bộ tách câu: edu.stanford.nlp.process.DocumentPreprocessor. Hãy thử lệnh: java edu.stanford.nlp.process.DocumentPreprocessor /u/nlp/data/lexparser/textDocument.txt> oneTokenizedSentencePerLine.txt. (Điều này được thực hiện thông qua một FSM (tốt nhưng heuristic), vì vậy nó nhanh chóng, bạn không chạy trình phân tích cú pháp xác suất.) –

2

Thật không may tôi không phải là một anh chàng ruby ​​nhưng có thể một ví dụ trong perl sẽ giúp bạn đi đúng hướng. Sử dụng một cái nhìn không phù hợp phía sau cho dấu chấm câu kết thúc sau đó một số trường hợp đặc biệt trong một không đằng sau theo sau bởi bất kỳ số lượng không gian tiếp theo là nhìn về phía trước cho một bức thư vốn. Tôi chắc chắn điều này không hoàn hảo nhưng tôi hy vọng nó chỉ cho bạn đi đúng hướng. Không chắc chắn cách bạn sẽ biết nếu Hoa Kỳ thực sự ở cuối câu ...

#!/usr/bin/perl 

$string = "Mr. Thompson is from the U.S.A. and is 75 years old. Dr. Bob is a dentist. This is a string that contains several sentances. For example this is one. Followed by another. Can it deal with a question? It sure can!"; 

my @sentances = split(/(?:(?<=\.|\!|\?)(?<!Mr\.|Dr\.)(?<!U\.S\.A\.)\s+(?=[A-Z]))/, $string); 

for (@sentances) { 
    print $_."\n"; 
} 
5

Hãy nhìn vào splitter Python câu trong NLTK (Công cụ ngôn ngữ tự nhiên Kit):

Punkt sentence tokenizer

Nó dựa trên các giấy tờ sau đây:

Kiss, Tibor và Strunk, Jan (2006): Unsupervised Multilingual Sentence Boundary Detection. Ngôn ngữ học tính toán 32: 485-525.

Cách tiếp cận trong bài báo khá thú vị. Chúng làm giảm vấn đề chia tách câu thành vấn đề xác định mức độ mạnh mẽ của một từ được liên kết với dấu chấm câu sau đây. Quá tải các khoảng thời gian sau khi viết tắt chịu trách nhiệm cho hầu hết các khoảng thời gian mơ hồ, vì vậy nếu bạn có thể xác định các từ viết tắt bạn có thể xác định ranh giới câu với xác suất cao.

Tôi đã thử nghiệm công cụ này một cách không chính thức một chút và có vẻ như cung cấp kết quả tốt cho nhiều ngôn ngữ (con người) khác nhau.

Chuyển nó sang Ruby sẽ không nhỏ, nhưng nó có thể cung cấp cho bạn một số ý tưởng.

0

THANKS!

Tôi thực sự thích thảo luận này, vì vậy tôi đã quan tâm đến trình phân tích cú pháp. Tôi đã thử nó và tôi đã viết ra một số ghi chú về cách để có được tất cả mọi thứ làm việc với Ruby và hoặc Rails!

Đang cố gắng để đi với các biểu thức chính quy là một cơn ác mộng ..

my 2 cents

+0

Trang này không còn tồn tại nữa ... Gương? – DickieBoy

1

Câu trả lời của Tiến sĩ Manning là thích hợp nhất nếu bạn đang xem xét các JAVA (và Ruby quá trong cách cứng;)). Nó là ở đây,

Có một splitter câu: edu.stanford.nlp.process.DocumentPreprocessor . Hãy thử lệnh: java edu.stanford.nlp.process.DocumentPreprocessor /u/nlp/data/lexparser/textDocument.txt

oneTokenizedSentencePerLine.txt. (Điều này được thực hiện thông qua một (tốt nhưng heuristic) FSM, do đó, nó nhanh; bạn không chạy phân tích cú pháp xác suất.)

Nhưng một gợi ý nhỏ nếu chúng ta thay đổi edu.stanford lệnh java .nlp.process.DocumentPreprocessor /u/nlp/data/lexparser/textDocument.txt> oneTokenizedSentencePerLine.txt ĐẾN java edu.stanford.nlp.process.DocumentPreprocessor -file/u/NLP/data/lexparser/textDocument. txt> oneTokenizedSentencePerLine.txt. Nó sẽ hoạt động tốt vì bạn cần phải xác định loại tệp nào đang được trình bày dưới dạng đầu vào. So -file cho tệp văn bản, -html cho HTML, v.v.

1

Tôi chưa thử nhưng nếu tiếng Anh là ngôn ngữ duy nhất bạn quan tâm, tôi khuyên bạn nên xem Lingua::EN::Readability.

Lingua :: EN :: Dễ đọc là mô-đun Ruby tính toán số liệu thống kê trên văn bản tiếng Anh. Nó có thể cung cấp số lượng từ, câu và âm tiết. Nó cũng có thể tính toán một số biện pháp dễ đọc, chẳng hạn như chỉ số Sương mù và mức Flesch-Kincaid. Các gói phần mềm bao gồm các mô-đun Lingua :: EN :: Sentence, mà phá vỡ văn bản tiếng Anh thành câu chú ý đến chữ viết tắt, và Lingua :: EN :: Âm tiết, có thể đoán số lượng âm tiết trong một từ tiếng Anh bằng văn bản.Nếu một cuốn từ điển phát âm có sẵn nó có thể tra cứu số lượng âm tiết trong từ điển cho chính xác hơn

Các bit bạn muốn là trong sentence.rb như sau:

module Lingua 
module EN 
# The module Lingua::EN::Sentence takes English text, and attempts to split it 
# up into sentences, respecting abbreviations. 

module Sentence 
    EOS = "\001" # temporary end of sentence marker 

    Titles = [ 'jr', 'mr', 'mrs', 'ms', 'dr', 'prof', 'sr', 'sen', 'rep', 
     'rev', 'gov', 'atty', 'supt', 'det', 'rev', 'col','gen', 'lt', 
     'cmdr', 'adm', 'capt', 'sgt', 'cpl', 'maj' ] 

    Entities = [ 'dept', 'univ', 'uni', 'assn', 'bros', 'inc', 'ltd', 'co', 
     'corp', 'plc' ] 

    Months = [ 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 
     'aug', 'sep', 'oct', 'nov', 'dec', 'sept' ] 

    Days  = [ 'mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun' ] 

    Misc  = [ 'vs', 'etc', 'no', 'esp', 'cf' ] 

    Streets = [ 'ave', 'bld', 'blvd', 'cl', 'ct', 'cres', 'dr', 'rd', 'st' ] 

    @@abbreviations = Titles + Entities + Months + Days + Streets + Misc 

    # Split the passed text into individual sentences, trim these and return 
    # as an array. A sentence is marked by one of the punctuation marks ".", "?" 
    # or "!" followed by whitespace. Sequences of full stops (such as an 
    # ellipsis marker "..." and stops after a known abbreviation are ignored. 
    def Sentence.sentences(text) 

    text = text.dup 

    # initial split after punctuation - have to preserve trailing whitespace 
    # for the ellipsis correction next 
    # would be nicer to use look-behind and look-ahead assertions to skip 
    # ellipsis marks, but Ruby doesn't support look-behind 
    text.gsub!(/([\.?!](?:\"|\'|\)|\]|\})?)(\s+)/) { $1 << EOS << $2 } 

    # correct ellipsis marks and rows of stops 
    text.gsub!(/(\.\.\.*)#{EOS}/) { $1 } 

    # correct abbreviations 
    # TODO - precompile this regex? 
    text.gsub!(/(#{@@abbreviations.join("|")})\.#{EOS}/i) { $1 << '.' } 

    # split on EOS marker, strip gets rid of trailing whitespace 
    text.split(EOS).map { | sentence | sentence.strip } 
    end 

    # add a list of abbreviations to the list that's used to detect false 
    # sentence ends. Return the current list of abbreviations in use. 
    def Sentence.abbreviation(*abbreviations) 
    @@abbreviations += abbreviations 
    @@abbreviations 
    end 
end 
end 
end 
+1

Điểm tuyệt vời được liệt kê trong đó, mặc dù tôi thấy rằng cho mục đích tốc độ trên một lượng lớn văn bản, thay vì làm nhiều egex thay thế, nó làm việc tốt để có một loạt các từ được chu kỳ thông qua, sau đó so sánh về các điều khoản bạn đã đề cập ở trên và với các tùy chọn kết thúc dòng khác. Nhanh hơn khoảng 1000 lần trong các thử nghiệm giới hạn của tôi đối với tài liệu có kích thước lớn. – JayCrossler

1

Đồng ý với câu trả lời được chấp nhận, sử dụng Stanford Core NLP là không có trí tuệ.

Tuy nhiên, trong năm 2016 có một số incompatibilities giao tiếp với Stanford Parser với các phiên bản sau của lõi nilp stanford (Tôi gặp sự cố với Stanford Core NLP v3.5).

Dưới đây là những gì tôi đã làm để phân tích văn bản thành câu sử dụng của Ruby interfacing với Stanford Lõi NLP:

  1. Cài đặt Stanford CoreNLP gem - nó hoạt động vẫn duy trì và, nó đã là một cuộc đấu tranh để tìm NLP ruby đá quý mà làm việc gần đây:

    gem install stanford-core-nlp

  2. sau đó theo các hướng dẫn trên readme for Using the latest version of the Stanford CoreNLP:

Sử dụng phiên bản mới nhất của Stanford CoreNLP (phiên bản 3.5.0 như của 31/10/2014) đòi hỏi một số bước thủ công thêm:

  • Tải Stanford CoreNLP version 3.5.0 từ http://nlp.stanford.edu/.

  • Đặt nội dung của bản lưu trữ được trích xuất bên trong thư mục/bin/ đá quý stanford-core-nlp (ví dụ: [...]/gems/stanford-core-nlp-0.x/bin /) hoặc bên trong vị trí thư mục được định cấu hình bằng cách đặt StanfordCoreNLP.jar_path.

  • Tải xuống full Stanford Tagger version 3.5.0 từ http://nlp.stanford.edu/.
  • Tạo thư mục có tên 'taggers' bên trong thư mục/bin/của đá quý stanford-core-nlp (ví dụ: [...]/gems/stanford-core-nlp-0.x/bin /) hoặc bên trong thư mục được định cấu hình bằng cách đặt StanfordCoreNLP.jar_path.
  • Đặt nội dung của lưu trữ được trích xuất trong thư mục trình gắn thẻ.
  • Tải xuống the bridge.jar file từ https://github.com/louismullie/stanford-core-nlp.
  • Đặt tệp bridger.jar đã tải xuống bên trong thư mục/bin/của đá quý stanford-core-nlp (ví dụ: [...]/gems/stanford-core-nlp-0.x/bin/taggers /) hoặc bên trong thư mục được định cấu hình bằng cách đặt StanfordCoreNLP.jar_path.

Sau đó mã ruby ​​để chia văn bản thành câu:

require "stanford-core-nlp" 

#I downloaded the StanfordCoreNLP to a custom path: 
StanfordCoreNLP.jar_path = "/home/josh/stanford-corenlp-full-2014-10-31/" 

StanfordCoreNLP.use :english 
StanfordCoreNLP.model_files = {} 
StanfordCoreNLP.default_jars = [ 
    'joda-time.jar', 
    'xom.jar', 
    'stanford-corenlp-3.5.0.jar', 
    'stanford-corenlp-3.5.0-models.jar', 
    'jollyday.jar', 
    'bridge.jar' 
] 

pipeline = StanfordCoreNLP.load(:tokenize, :ssplit) 

text = 'Mr. Josh Weir is writing some code. ' + 
    'I am Josh Weir Sr. my son may be Josh Weir Jr. etc. etc.' 
text = StanfordCoreNLP::Annotation.new(text) 
pipeline.annotate(text) 
text.get(:sentences).each{|s| puts "sentence: " + s.to_s} 

#output: 
#sentence: Mr. Josh Weir is writing some code. 
#sentence: I am Josh Weir Sr. my son may be Josh Weir Jr. etc. etc. 
Các vấn đề liên quan