Javascript (jQuery) удалить последнее предложение длинного текста

Я ищу функцию javascript, которая достаточно умна, чтобы удалить последнее предложение длинного фрагмента текста (фактически один абзац). Некоторый пример текста, чтобы показать сложность:

<p>Blabla, some more text here. Sometimes <span>basic</span> html code is used but that should not make the "selection" of the sentence any harder! I looked up the window and I saw a plane flying over. I asked the first thing that came to mind: "What is it doing up there?" She did not know, "I think we should move past the fence!", she quickly said. He later described it as: "Something insane."</p>

Теперь я мог бы разделить на . и удалить последнюю запись массива, но это не сработает для предложений, заканчивающихся на ? или !, а некоторые предложения заканчиваются кавычками, такими как something: "stuff."

function removeLastSentence(text) {
  sWithoutLastSentence = ...; // ??
  return sWithoutLastSentence;
}

Как это сделать? Какой правильный алгоритм?

Редактировать. Под длинным текстом я подразумеваю все содержимое абзаца, а под предложением я подразумеваю фактическое предложение (а не строку), поэтому в моем примере последнее предложение: He later described it as: "Something insane." Когда оно удалено, следующий She did not know, "I think we should move past the fence!", she quickly said."


person sougonde    schedule 23.09.2011    source источник
comment
Определите последнее предложение и длинную строку. Если вы ищете метод ограничения количества строк в тексте, см. этот ответ.   -  person Rob W    schedule 23.09.2011
comment
Отредактировал мой вопрос, под предложением я подразумеваю реальное предложение, см. выше. :)   -  person sougonde    schedule 23.09.2011
comment
Позже он описал это как нечто безумное. Я не специалист по английскому языку... но так ли это? или должно быть Позже он описал это как нечто безумное.   -  person rlemon    schedule 23.09.2011
comment
Я согласен с вами, я предпочитаю последнее, но книга, которую я обрабатываю, использует и то, и другое, так что... Редактирование исходного кода - это мошенничество, а исходник довольно большой.   -  person sougonde    schedule 23.09.2011
comment
Трудно разделить абзац за предложением, если предложения не все структурированы должным образом ... Я бы не очень верил, что решение будет последовательным.   -  person rlemon    schedule 23.09.2011
comment
@rlemon да, если текст игнорирует языковые правила, вы не можете легко обнаружить отдельные предложения.   -  person c69    schedule 23.09.2011


Ответы (3)


Определите свои правила: // 1. Предложение начинается с заглавной буквы // 2. Предложению не предшествует ничего или [.!?], но не [,:;] // 3. Предложению могут предшествовать кавычки, если оно не отформатировано должным образом, например, ["'] // 4. В этом случае предложение может быть неправильным, если слово, следующее за кавычкой, является именем

Какие-то дополнительные правила?

Определите цель: // 1. Удалите последнее предложение

Предположения. Если вы начали с последнего символа в текстовой строке и работали в обратном направлении, то вы определили бы начало предложения как: 1. Текстовая строка перед символом [.? !] ИЛИ 2. Строка текста перед символом ["'] и перед ней заглавная буква 3. Каждому [.] предшествует пробел 4. Мы не исправляем HTML-теги 5. Эти предположения неверны надежен и требует регулярной адаптации

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

var characterGroups = $('#this-paragraph').html().split(' ').reverse();

Если ваша строка:

Блабла, еще немного текста здесь. Иногда используется базовый HTML-код, но это не должно усложнять "выбор" предложения! Я посмотрел в окно и увидел пролетавший мимо самолет. Я спросил первое, что пришло в голову: «Что он там делает?» Она не знала: «Я думаю, мы должны пройти мимо забора!», - быстро сказала она. Позже он описал это как: «Что-то безумное».

var originalString = 'Blabla, some more text here. Sometimes <span>basic</span> html code is used but that should not make the "selection" of the sentence any harder! I looked up the window and I saw a plane flying over. I asked the first thing that came to mind: "What is it doing up there?" She did not know, "I think we should move past the fence!", she quickly said. He later described it as: "Something insane."';

Тогда ваш массив в characterGroups будет:

    ["insane."", ""Something", "as:", "it", "described", "later", "He",
 "said.", "quickly", "she", "fence!",", "the", "past", "move", "should", "we",
 "think", ""I", "know,", "not", "did", "She", "there?"", "up", "doing", "it",
 "is", ""What", "mind:", "to", "came", "that", "thing", "first", "the", "asked",
 "I", "over.", "flying", "plane", "a", "saw", "I", "and", "window", "the", "up",
 "looked", "I", "harder!", "any", "sentence", "the", "of", ""selection"", "the",
 "make", "not", "should", "that", "but", "used", "is", "code", "html", "basic",
 "Sometimes", "here.", "text", "more", "some", "Blabla,"]

Примечание. теги '' и другие теги будут удалены с помощью метода .text() в jQuery

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

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

var found = false;
var index = null;

Прокрутите массив и найдите любой элемент, оканчивающийся на [.!?] ИЛИ оканчивающийся на ", где предыдущий элемент начинался с заглавной буквы.

var position     = 1,//skip the first one since we know that's the end anyway
    elements     = characterGroups.length,
    element      = null,
    prevHadUpper = false,
    last         = null;

while(!found && position < elements) {
    element = characterGroups[position].split('');

    if(element.length > 0) {
       last = element[element.length-1];

       // test last character rule
       if(
          last=='.'                      // ends in '.'
          || last=='!'                   // ends in '!'
          || last=='?'                   // ends in '?'
          || (last=='"' && prevHadUpper) // ends in '"' and previous started [A-Z]
       ) {
          found = true;
          index = position-1;
          lookFor = last+' '+characterGroups[position-1];
       } else {
          if(element[0] == element[0].toUpperCase()) {
             prevHadUpper = true;
          } else {
             prevHadUpper = false;
          }
       }
    } else {
       prevHadUpper = false;
    }
    position++;
}

Если вы запустите приведенный выше скрипт, он правильно определит «He» как начало последнего предложения.

console.log(characterGroups[index]); // He at index=6

Теперь вы можете запустить строку, которая у вас была раньше:

var trimPosition = originalString.lastIndexOf(lookFor)+1;
var updatedString = originalString.substr(0,trimPosition);
console.log(updatedString);

// Blabla, some more text here. Sometimes <span>basic</span> html code is used but that should not make the "selection" of the sentence any harder! I looked up the window and I saw a plane flying over. I asked the first thing that came to mind: "What is it doing up there?" She did not know, "I think we should move past the fence!", she quickly said.

Запустите его еще раз и получите: Блабла, здесь еще немного текста. Иногда используется базовый HTML-код, но это не должно усложнять "выбор" предложения! Я посмотрел в окно и увидел пролетавший мимо самолет. Я спросил первое, что пришло в голову: «Что он там делает?»

Запустите его еще раз и получите: Блабла, здесь еще немного текста. Иногда используется базовый HTML-код, но это не должно усложнять "выбор" предложения! Я посмотрел в окно и увидел пролетавший мимо самолет.

Запустите его еще раз и получите: Блабла, здесь еще немного текста. Иногда используется базовый HTML-код, но это не должно усложнять "выбор" предложения!

Запустите его еще раз и получите: Блабла, здесь еще немного текста.

Запустите его еще раз и получите: Блабла, здесь еще немного текста.

Итак, я думаю, что это соответствует тому, что вы ищете?

Как функция:

function trimSentence(string){
    var found = false;
    var index = null;

    var characterGroups = string.split(' ').reverse();

    var position     = 1,//skip the first one since we know that's the end anyway
        elements     = characterGroups.length,
        element      = null,
        prevHadUpper = false,
        last         = null,
        lookFor      = '';

    while(!found && position < elements) {
        element = characterGroups[position].split('');

        if(element.length > 0) {
           last = element[element.length-1];

           // test last character rule
           if(
              last=='.' ||                // ends in '.'
              last=='!' ||                // ends in '!'
              last=='?' ||                // ends in '?'
              (last=='"' && prevHadUpper) // ends in '"' and previous started [A-Z]
           ) {
              found = true;
              index = position-1;
              lookFor = last+' '+characterGroups[position-1];
           } else {
              if(element[0] == element[0].toUpperCase()) {
                 prevHadUpper = true;
              } else {
                 prevHadUpper = false;
              }
           }
        } else {
           prevHadUpper = false;
        }
        position++;
    }


    var trimPosition = string.lastIndexOf(lookFor)+1;
    return string.substr(0,trimPosition);
}

Тривиально сделать для него плагин, но остерегайтесь ПРЕДПОЛОЖЕНИЙ! :)

Это помогает?

Спасибо, АЕ

person MyStream    schedule 01.10.2011

Это должно сделать это.

/*
Assumptions:
- Sentence separators are a combination of terminators (.!?) + doublequote (optional) + spaces + capital letter. 
- I haven't preserved tags if it gets down to removing the last sentence. 
*/
function removeLastSentence(text) {

    lastSeparator = Math.max(
        text.lastIndexOf("."), 
        text.lastIndexOf("!"), 
        text.lastIndexOf("?")
    );

    revtext = text.split('').reverse().join('');
    sep = revtext.search(/[A-Z]\s+(\")?[\.\!\?]/); 
    lastTag = text.length-revtext.search(/\/\</) - 2;

    lastPtr = (lastTag > lastSeparator) ? lastTag : text.length;

    if (sep > -1) {
        text1 = revtext.substring(sep+1, revtext.length).trim().split('').reverse().join('');
        text2 = text.substring(lastPtr, text.length).replace(/['"]/g,'').trim();

        sWithoutLastSentence = text1 + text2;
    } else {
        sWithoutLastSentence = '';
    }
    return sWithoutLastSentence;
}

/*
TESTS: 

var text = '<p>Blabla, some more text here. Sometimes <span>basic</span> html code is used but that should not make the "selection" of the text any harder! I looked up the window and I saw a plane flying over. I asked the first thing that came to mind: "What is it doing up there?" She did not know, "I think we should move past the fence!", she quickly said. He later described it as: "Something insane. "</p>';

alert(text + '\n\n' + removeLastSentence(text));
alert(text + '\n\n' + removeLastSentence(removeLastSentence(text)));
alert(text + '\n\n' + removeLastSentence(removeLastSentence(removeLastSentence(text))));
alert(text + '\n\n' + removeLastSentence(removeLastSentence(removeLastSentence(removeLastSentence(text)))));
alert(text + '\n\n' + removeLastSentence(removeLastSentence(removeLastSentence(removeLastSentence(removeLastSentence(text))))));
alert(text + '\n\n' + removeLastSentence(removeLastSentence(removeLastSentence(removeLastSentence(removeLastSentence(removeLastSentence(text)))))));
alert(text + '\n\n' + removeLastSentence('<p>Blabla, some more text here. Sometimes <span>basic</span> html code is used but that should not make the "selection" of the text any harder! I looked up the '));
*/
person Poojan    schedule 03.10.2011

Это хороший. Почему бы вам не создать временную переменную, преобразовать все '!' и '?' на '.', разделить эту временную переменную, удалить последнее предложение, объединить этот временный массив в строку и взять ее длину? Затем подстроите исходный абзац до этой длины.

person EHorodyski    schedule 23.09.2011
comment
Или эй, просто используйте Regex, и это намного проще = P - person EHorodyski; 23.09.2011
comment
На самом деле, заменив ." в конце предложения, я мог бы обойтись только /[\.!?]/, регулярным выражением, которое упоминал @omnosis. - person sougonde; 23.09.2011
comment
Вы по-прежнему будете сталкиваться с проблемой с предложениями, содержащими кавычки с пунктуацией в конце, как в вашем образце. - person samiz; 23.09.2011
comment
Вы можете заменить все кавычки, за которыми следует пробел и заглавная буква, точками для временной строки, а затем удалить все пустые элементы массива. - person EHorodyski; 27.09.2011