2015-01-31 3 views
2

Использование Ruby, я хочу найти регулярное выражение, которое правильно идентифицирует границы предложения, которое я определяю как любую строку, которая заканчивается на [.!?], За исключением случаев, когда эти знаки препинания существуют в цитате знаки, как вРегулярное выражение выражение/обратная связь для шаблонов пунктуации

Мой друг сказал: «Джон здесь нет!» и затем он ушел.

Моего текущий код, который падает короткое есть:

text = para.text.scan(/[^\.!?]+[(?<!(.?!)\"|.!?] /).map(&:strip) 

Я корпел над регулярными выражениями документов, но до сих пор не могу правильно понять lookbacks/lookaheads.

+1

Рассмотрите: «Джек хороший мальчик, я уверен, что он!». Один или два предложения? Возможно, вам нужно только учитывать двойные кавычки. –

+0

@CarySwoveland Хорошая точка. Как бы вы решили заняться что, чтобы каждое предложение было чистым? Я использую Википедию в качестве источников, а затем извлекаю предложения для тестирования детей на пунктуацию. –

+0

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

ответ

2

Как насчет чего-то подобного?

/(?:"(?>[^"]|\\.)+"|[a-z]\.[a-z]\.|[^.?!])+[!.?]/gi

Демо: https://regex101.com/r/bJ8hM5/2

Как это работает: регулярное выражение, будет в каждой позиции в строке, проверьте следующее

  1. строка в кавычках в виде " цитата ", которая может содержать ничего до конца цитаты. Вы также можете получить скрытые кавычки, например "hell\"o".
  2. Соответствует любой букве, за которой следует точка, а затем другая буква и, наконец, точка. Это должно соответствовать вашему специальному случаю U.S. и т. Д.
  3. Сопоставьте все остальное, что не является символом пунктуации .?!.
  4. Повторяйте до тех пор, пока мы не достигнем символа пунктуации.
+0

Не могли бы вы объяснить это так, чтобы я мог понять следующий раз более четко? –

+0

Кроме того, в моем реальном мире есть случайные ложные срабатывания, генерируемые такими строками, как 'U.S.' - Если бы вы могли отредактировать свой ответ, включив его, не включая это, я был бы благодарен. –

+0

Несомненно, он был скорректирован. –

1

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

код

def extract_sentences(str, da_terminators) 
    start_with_quote = (str[0] == '"') 
    str.split(/(\".*?\")/) 
    .flat_map.with_index { |b,i| 
     (start_with_quote == i.even?) ? b : b.split(/([#{da_terminators}])/) } 
    .slice_after(/^[#{da_terminators}]$/) 
    .map { |sb| sb.join.strip } 
end 

Пример

puts extract_sentences(str, '!?.') 
    # My friend said "John isn't here!", then "I'm outta' here" and then he left. 
    # Let's go! 
    # Later, he said "Aren't you coming?" 

Объяснение

str Для выше и

da_terminators = '!?.' 

Нам необходимо следующее позже:

start_with_quote = (str[0] == '"') 
    #=> false 

Разделить строку на "...". Мы должны сделать \".*?\" группой захвата, чтобы сохранить ее в split. Результатом является массив, block, который поочередно имеет строки, окруженные двойными кавычками и другими строками. start_with_quote рассказывает нам, что есть.

blocks = str.split(/(\".*?\")/) 
    #=> ["My friend said ", 
    # "\"John isn't here!\"", 
    # ", then ", 
    # "\"I'm outta' here\"", 
    # " and then he left. Let's go! Later, he said ", 
    # "\"Aren't you coming?\""] 

Разделить элементы строки, которые не окружены двойными кавычками. Разделение происходит на любом из символов, заканчивающих предложение. Опять же, это должно быть в группе захвата, чтобы сохранить разделитель.

new_blocks = blocks.flat_map.with_index { |b,i| 
    (start_with_quote == i.even?) ? b : b.split(/([#{da_terminators}])/) } 
    #=> ["My friend said ", 
    # "\"John isn't here!\"", 
    # ", then ", 
    # "\"I'm outta' here\"", 
    # " and then he left", 
    # ".", 
    # " Let's go", 
    # "!", 
    # " Later, he said ", 
    # "\"Aren't you coming?\"" 

sentence_blocks_enum = new_blocks.slice_after(/^[#{da_terminators}]$/) 
    # #<Enumerator:0x007f9a3b853478> 

Convert это переписчик в массив, чтобы увидеть, что он будет проходить в его блок:

sentence_blocks_enum.to_a 
    #=> [["My friend said ", 
    #  "\"John isn't here!\"", 
    #  ", then ", 
    #  "\"I'm outta' here\"", 
    #  " and then he left", "."], 
    # [" Let's go", "!"], 
    # [" Later, he said ", "\"Aren't you coming?\""]] 

Объединить блоки каждого предложения и strip пробелов и возвращает массив:

sentence_blocks_enum.map { |sb| sb.join.strip } 
    #=> ["My friend said \"John isn't here!\", then \"I'm outta' here\" and then he left.", 
    # "Let's go!", 
    # "Later, he said \"Aren't you coming?\""] 
+0

хороший, спасибо. –

Смежные вопросы