¿Cómo puedo truncar mis cadenas con un "..." si son demasiado largas?

84

Espero que alguien tenga una buena idea. Tengo cadenas como esta:

abcdefg
abcde
abc

Lo que necesito es que estén trucados para mostrar así si tienen más de una longitud especificada:

abc ..
abc ..
abc

¿Hay algún código C # simple que pueda usar para esto?

Melonia
fuente
¿Dónde estás buscando hacer esto? - en una aplicación Forms o WPF o en un sitio web - ¡proporcione más detalles!
Barry Kaye
2
El problema con la mayoría de las soluciones es que utilizan un número de Chars como límite. Desafortunadamente, el ancho gráfico puede variar mucho. Y luego están los sustitutos UTF-16, combinando caracteres, ...
CodesInChaos
12
Esto NO es un duplicado de la pregunta sugerida. Esta es una pregunta muy general, mientras que el duplicado sugerido es una pregunta extremadamente específica.
JasonMArcher
2
Esto no es en absoluto un duplicado de la pregunta sugerida.
Set
2
Esta pregunta ni siquiera se acerca al duplicado sugerido, elimine el atributo duplicado. Gracias.
Daniel Leiszen

Respuestas:

146

Aquí está la lógica envuelta en un método de extensión:

public static string Truncate(this string value, int maxChars)
{
    return value.Length <= maxChars ? value : value.Substring(0, maxChars) + "...";
}

Uso:

var s = "abcdefg";

Console.WriteLine(s.Truncate(3));
Bryan Watts
fuente
1
Gracias Bryan. Tu respuesta se ve bien. Disculpe mi simple pregunta, pero ¿cómo puedo usar un método de extensión?
Melony
1
@Melony: editado para incluir el uso.
Bryan Watts
11
… (Puntos suspensivos) es el símbolo correcto para aquellos que se preocupan. Unicode U + 2026.
Malako
3
adición rápida para incluir un cheque nulo
james
1
gracias @Malako: value.Substring(0, maxChars) + (char)0x2026;
Pierre
8
public string TruncString(string myStr, int THRESHOLD)
{
    if (myStr.Length > THRESHOLD)
        return myStr.Substring(0, THRESHOLD) + "...";
    return myStr;
}

Ignore la convención de nomenclatura, es solo en caso de que realmente necesite la variable THRESHOLD o si siempre es del mismo tamaño.

Alternativamente

string res = (myStr.Length > THRESHOLD) ? myStr.Substring(0, THRESHOLD) + ".." : myStr;
Jesús Ramos
fuente
¿Es posible convertir esto en algo con una línea que pueda usar en línea?
Melony
2
Esto puede producir cadenas no válidas si divide un punto de código en el medio :(
CodesInChaos
7

Todas muy buenas respuestas, pero para limpiarlo un poco, si sus cadenas son oraciones, no rompa su cadena en medio de una palabra.

private string TruncateForDisplay(this string value, int length)
{
  if (string.IsNullOrEmpty(value)) return string.Empty;
  var returnValue = value;
  if (value.Length > length)
  {
    var tmp = value.Substring(0, length) ;
    if (tmp.LastIndexOf(' ') > 0)
       returnValue = tmp.Substring(0, tmp.LastIndexOf(' ') ) + " ...";
  }                
  return returnValue;
}
JStevens
fuente
Esta es la única respuesta que no divide las palabras. Por lo tanto, el único correcto en mi opinión.
mxmissile
@mxmissile - dados los datos de OP, para "abcdefg", truncar a los 3 caracteres, va a "abc ...", incluso si esto funcionara, no sería correcto en absoluto. Los datos de la muestra de OP indican claramente un truncado duro en medio del texto contiguo. Peor aún, esta respuesta generaría un error. Dado que los datos no contienen un espacio, LastIndexOfdevolvería -1 y Substringprovocaría un error de tiempo de ejecución.
4

Aquí hay una versión que tiene en cuenta la longitud de las elipses:

    public static string Truncate(this string value, int maxChars)
    {
        const string ellipses = "...";
        return value.Length <= maxChars ? value : value.Substring(0, maxChars - ellipses.Length) + ellipses;
    }
Jon
fuente
4
si utiliza el carácter de puntos suspensivos, entonces no es necesario. La longitud de los caracteres siempre será 1const char ellipse = (char)0x2026;
Pierre
3

No hay un método integrado en .NET Framework que haga esto, sin embargo, este es un método muy fácil de escribir usted mismo. Estos son los pasos, intente hacerlo usted mismo y háganos saber lo que se le ocurrió.

  1. Crea un método, quizás un método de extensión public static void TruncateWithEllipsis(this string value, int maxLength)

  2. Verifique si el valor pasado es mayor que el maxLengthespecificado usando la Lengthpropiedad . Si valueno es mayor que maxLength, devuelva el value.

  3. Si no devolvimos el valor pasado tal como está, entonces sabemos que necesitamos truncar. Entonces necesitamos obtener una sección más pequeña de la cadena usando el SubStringmétodo . Ese método devolverá una sección más pequeña de una cadena en función de un valor inicial y final especificado. La posición final es lo que pasó el maxLengthparámetro, así que utilícelo.

  4. Devuelve la subsección de la cadena más la elipsis.

Un gran ejercicio para más adelante sería actualizar el método y hacer que se rompa solo después de las palabras completas. También puede crear una sobrecarga para especificar cómo le gustaría mostrar que una cadena se ha truncado. Por ejemplo, el método podría devolver "(haga clic para obtener más)" en lugar de "..." si su aplicación está configurada para mostrar más detalles al hacer clic.

Beto
fuente
2

Código detrás:

string shorten(sting s)
{
    //string s = abcdefg;
    int tooLongInt = 3;

    if (s.Length > tooLongInt)
        return s.Substring(0, tooLongInt) + "..";

    return s;
}

Margen:

<td><%= shorten(YOUR_STRING_HERE) %></td>
VMAtm
fuente
¿Cómo podría encajar esto en: "<td>" + cadena + "<\ td>"?
Melony
2

Quizás sea mejor implementar un método para ese propósito:

string shorten(sting yourStr)
{
//Suppose you have a string yourStr, toView and a constant value 

    string toView;
    const int maxView = 3;

    if (yourStr.Length > maxView)
        toView = yourStr.Substring(0, maxView) + " ..."; // all you have is to use Substring(int, int) .net method
    else
        toView = yourStr;
return toView;
}

fuente
1
string s = "abcdefg";
if (s.length > 3)
{
    s = s.substring(0,3);
}

Puede utilizar la función Substring.

Jethro
fuente
1

Encontré esta pregunta después de buscar "C # truncate ellipsis". Usando varias respuestas, creé mi propia solución con las siguientes características:

  1. Un método de extensión
  2. Agregar una elipsis
  3. Haga que la elipsis sea opcional
  4. Valide que la cadena no sea nula ni esté vacía antes de intentar truncarla.

    public static class StringExtensions
    {
        public static string Truncate(this string value, 
            int maxLength, 
            bool addEllipsis = false)
        {
            // Check for valid string before attempting to truncate
            if (string.IsNullOrEmpty(value)) return value;
    
            // Proceed with truncating
            var result = string.Empty;
            if (value.Length > maxLength)
            {
                result = value.Substring(0, maxLength);
                if (addEllipsis) result += "...";
            }
            else
            {
                result = value;
            }
    
            return result;
        }
    }
    

Espero que esto ayude a alguien más.

Tod Birdsall
fuente
0

Claro, aquí hay un código de muestra:

string str = "abcdefg";
if (str.Length > X){
   str = str.Substring(0, X) + "...";
}
Justin Ethier
fuente
0

Tengo este problema recientemente. Estaba almacenando un mensaje de "estado" en un campo de base de datos nvarcharMAX que tiene 4000 caracteres. Sin embargo, mis mensajes de estado se estaban acumulando y golpeando la excepción.

Pero no fue un caso simple de truncamiento, ya que un truncamiento arbitrario dejaría huérfana a parte de un mensaje de estado, por lo que realmente necesitaba "truncar" en una parte consistente de la cadena.

Resolví el problema convirtiendo la cadena en una matriz de cadenas, eliminando el primer elemento y luego restaurando a una cadena. Aquí está el código ("CurrentStatus" es la cadena que contiene los datos) ...

        if (CurrentStatus.Length >= 3750)
        {
            // perform some truncation to free up some space.

            // Lets get the status messages into an array for processing...
            // We use the period as the delimiter, then skip the first item and re-insert into an array.

            string[] statusArray = CurrentStatus.Split(new string[] { "." }, StringSplitOptions.None)
                                    .Skip(1).ToArray();

            // Next we return the data to a string and replace any escaped returns with proper one.
            CurrentStatus = (string.Join(".", statusArray))
                                    .Replace("\\r\\n", Environment.NewLine);


        }

Espero que ayude a alguien.

Calle Darren
fuente