2011-09-23 14 views
6

Estoy buscando una función de JavaScript que sea lo suficientemente inteligente como para eliminar la última frase de un fragmento largo de texto (un párrafo en realidad). Algunos ejemplos de texto para mostrar la complejidad:Javascript (jQuery) eliminar la última frase del texto largo

<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> 

Ahora podría dividir en . y eliminar la última entrada de la matriz, pero que no funcionaría para frases que terminan con ? o ! y algunas frases terminar con citas como something: "stuff."

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

¿Cómo hacer esto? ¿Cuál es un algoritmo adecuado?

Editar - Por largo texto me refiero a todo el contenido en mi párrafo y por frase me refiero a una sentencia real (no una línea), por lo que en mi ejemplo la última frase es: He later described it as: "Something insane." Cuando se quita que uno, el el próximo es She did not know, "I think we should move past the fence!", she quickly said."

+0

Define "última oración" y "cadena larga". Si está buscando un método para limitar el número de líneas en un texto, consulte ** [esta respuesta] (http://stackoverflow.com/questions/7519337/given-a-textarea-is-there-a- way-to-restrict-length-based-on-of-lines/7521855 # 7521855) **. –

+0

Editado mi pregunta, por frase me refiero a una oración real, ver más arriba. :) – bartolsthoorn

+0

*** Más tarde lo describió como: "Algo loco". *** No soy un comandante inglés ... ¿pero es correcto? o debería ser *** Más tarde lo describió como, "Algo loco". *** – rlemon

Respuesta

2

definir sus reglas: [.!?] // 1. Una oración comienza con una letra mayúscula // 2. Una sentencia es precedido por nada o, pero not [,:;] // 3. Una oración puede ir precedida de comillas si no se formatea correctamente, como ["'] // 4. Una oración puede ser incorrecta en este caso si la palabra que sigue a una cita es una Nombre

otras reglas adicionales

definir su propósito: // 1. Retire la última frase

Supuestos: Si ha iniciado desde el último carácter de la cadena de texto y trabajó hacia atrás, entonces sería identificar el comienzo de la oración como: 1. La cadena de texto antes del carácter es [.?!] O 2. La cadena de texto antes del carácter es ["'] y va precedida de una Mayúscula 3. Cada [.] Va precedido de un espacio 4. No estamos corrigiendo las etiquetas html 5. Estas suposiciones no son sólidas y deberán adaptarse regularmente

Solución posible: Lea en su cadena y divídalo en el carácter de espacio para darnos trozos de cadenas para revisar al revés.

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

Si la cadena es:

Blabla, algo más de texto aquí. A veces se usa el código html básico, pero eso no debería hacer más difícil la "selección" de la oración. Miré por la ventana y vi un avión volando. Le pregunté a la primera cosa que me vino a la mente: "¿Qué está haciendo allí?" Ella no sabía, "¡Creo que deberíamos pasar la valla!", Dijo rápidamente. Más tarde lo describió como: "Algo loco"."

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."'; 

Luego, su matriz en characterGroups sería:

["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,"] 

Nota:las '' etiquetas y otros serían eliminadas mediante el método .text() en jQuery

A cada bloque le sigue un espacio, así que cuando hayamos identificado nuestra posición de inicio de frase (por índice de matriz) sabremos qué índice tenía el espacio y podemos dividir la cadena original en el l ocación donde el espacio ocupa ese índice desde el final de la oración.

darnos una variable para marcar si lo hemos encontrado o no, y una variable para contener la posición de índice del elemento de matriz que identificamos como la celebración del inicio de la última frase:

var found = false; 
var index = null; 

bucle a través la matriz y buscar cualquier elemento que termina en [.!?] o termine en "donde el elemento anterior comenzó con una letra mayúscula.

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++; 
} 

Si ejecuta el script anterior se identificará correctamente 'Él' como el comienzo de la última oración.

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

Ahora se puede ejecutar a través de la cadena que tenía antes:

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. 

ejecutarlo de nuevo y obtener: Blabla, algo más de texto aquí. A veces se usa el código html básico, pero eso no debería hacer más difícil la "selección" de la oración. Miré por la ventana y vi un avión volando. Le pregunté a la primera cosa que me vino a la mente: "¿Qué está haciendo allí?"

Ejecútelo de nuevo y obtenga: Blabla, más texto aquí. A veces se usa el código html básico, pero eso no debería hacer más difícil la "selección" de la oración. Miré por la ventana y vi un avión volando.

Ejecútelo de nuevo y obtenga: Blabla, más texto aquí. A veces se usa el código html básico, pero eso no debería hacer más difícil la "selección" de la oración.

Ejecútelo de nuevo y obtenga: Blabla, más texto aquí.

Ejecútelo de nuevo y obtenga: Blabla, más texto aquí.

Entonces, I piensa que coincide con lo que está buscando?

En función:

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); 
} 

Es trivial para hacer un plugin para que si, pero cuidado con las suposiciones! :)

¿Ayuda esto?

Gracias, AE

0

Esta es una buena idea. ¿Por qué no creas una variable temporal, conviertes todo '!' y '?' en '.', divida esa variable temporal, elimine la última oración, combine esa matriz temporal en una cadena y tome su longitud? Entonces subcadena el párrafo original hasta que la longitud

+0

Oye, solo usa Regex y es mucho más fácil = P – EHorodyski

+0

En realidad, al reemplazar '." 'Al final de una oración, podría salirte con' /[\.!?]/ ', la expresión regular que dice @omnosis mencionado. – bartolsthoorn

+0

Todavía se encontrará con un problema con oraciones que contengan comillas con puntuación final, como en su ejemplo. – samiz

1

Esto debería hacerlo.

/* 
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 ')); 
*/ 
+0

¡Gracias por su código! – bartolsthoorn

+0

He reescrito su entrada en coffeescript https://gist.github.com/1270335 – bartolsthoorn

Cuestiones relacionadas