Domanda

Voglio fit stringhe in una specifica larghezza.Esempio, "Ciao mondo" -> "...il mondo", "Ciao...", "Lui...rld".

Sapete dove posso trovare il codice per che?E ' un trucchetto molto utile per la rappresentazione di informazioni, e vorrei aggiungere nel mio applicazioni (ovviamente).

Modifica:Scusate, ho dimenticato di citare il Font parte.Non solo per la larghezza fissa stringhe, ma secondo il tipo di carattere.

È stato utile?

Soluzione

E 'una bella semplice algoritmo per scrivere se non si può trovare da nessuna parte - lo pseudocodice sarebbe qualcosa di simile:

if theString.Length > desiredWidth:
    theString = theString.Left(desiredWidth-3) + "...";

o se volete i puntini di sospensione all'inizio della stringa, che seconda linea potrebbe essere:

    theString = "..." + theString.Right(desiredWidth-3);

o se lo vuoi in mezzo:

    theString = theString.Left((desiredWidth-3)/2) + "..." + theString.Right((desiredWidth-3)/2 + ((desiredWidth-3) mod 2))

Modifica
Darò per scontato che si sta utilizzando MFC. Dal momento che hai intenzione con i font, è possibile utilizzare il CDC :: funzione GetOutputTextExtent . Prova:

CString fullString
CSize size = pDC->GetOutputTextExtent(fullString);
bool isTooWide = size.cx > desiredWidth;

Se questo è troppo grande, allora si può poi fare una ricerca per cercare di trovare la stringa più lunga che si può andare bene; e potrebbe essere il più intelligente una ricerca come si vuole - per esempio, si può solo cercare di "Ciao Worl ..." e poi "Ciao Wor ..." e poi "Ciao Wo ..."; la rimozione di un carattere finché non si trova si adatta. In alternativa, si potrebbe fare una ricerca binaria - provare "Ciao Worl ..." - se che doesn 't lavoro, allora basta usare la metà dei caratteri del testo originale: 'Ciao ...' - se che si adatta, provare a metà strada tra essa e: 'Ciao Wo ...' fino a trovare la più lunga che fa ancora in forma. Oppure si potrebbe provare qualche euristica stima (dividere la lunghezza totale per la lunghezza desiderata, in proporzione stimare il numero di caratteri, e la ricerca da lì.

La soluzione più semplice è qualcosa di simile:

unsigned int numberOfCharsToUse = fullString.GetLength();
bool isTooWide = true;
CString ellipsis = "...";
while (isTooWide)
{
    numberOfCharsToUse--;
    CString string = fullString.Left(numberOfCharsToUse) + ellipsis;
    CSize size = pDC->GetOutputTextExtent(string);
    isTooWide = size.cx > desiredWidth;
}

Altri suggerimenti

E 'davvero piuttosto banale; Non credo che troverete codice specifico se non si ha qualcosa di più strutturato in mente.

Che, fondamentalmente, desidera:

  1. per ottenere la lunghezza della stringa che hai, e la larghezza della finestra.
  2. capire quante charaters si può prendere dalla stringa originale, che sarà essere sostanzialmente finestra larghezza-3. Chiamata che k .
  3. A seconda se si vuole mettere i puntini di sospensione a metà o alla fine della mano destra, prendere il primo piano (k / 2) caratteri da un capo all'altro, concatenato con "...", poi concatenato con l'ultimo piano (k / 2) caratteri (possibilmente un altro carattere necessaria a causa della divisione); o prendere i primi caratteri k, susseguono da "...".

Credo che la risposta di Smashery è un buon inizio. Un modo per raggiungere il risultato finale sarebbe quello di scrivere del codice di test con alcuni ingressi di prova e risultati desiderati. Una volta che hai un buon set di configurazione test, è possibile implementare il codice di manipolazione di stringhe fino ad ottenere tutti i test per passare.

  • calcolare la larghezza del testo ( sulla base del tipo di carattere)

Nel caso in cui si utilizza MFC l'API GetOutputTextExtent ti porterà il valore.

  • se la larghezza supera il dato larghezza specifica, calcolare la larghezza dell'ellisse prima:

    ellipseWidth = calcolare la larghezza di (...)

  • Rimuovere la parte stringa con larghezza ellipseWidth dall'estremità e aggiungere ellisse.

    qualcosa di simile: Ciao ...

Per coloro che sono interessati per una completa routine, questo è il mio risposta :

/**
 *  Returns a string abbreviation
 *  example: "hello world" -> "...orld" or "hell..." or "he...rd" or "h...rld"
 *
 *  style:
      0: clip left
      1: clip right
      2: clip middle
      3: pretty middle
 */
CString*
strabbr(
  CDC* pdc,
  const char* s,
  const int area_width,
  int style  )
{
  if (  !pdc || !s || !*s  ) return new CString;

  int len = strlen(s);
  if (  pdc->GetTextExtent(s, len).cx <= area_width  ) return new CString(s);

  int dots_width = pdc->GetTextExtent("...", 3).cx;
  if (  dots_width >= area_width  ) return new CString;

  // My algorithm uses 'left' and 'right' parts of the string, by turns.
  int n = len;
  int m = 1;
  int n_width = 0;
  int m_width = 0;
  int tmpwidth;
  // fromleft indicates where the clip is done so I can 'get' chars from the other part
  bool  fromleft = (style == 3  &&  n % 2 == 0)? false : (style > 0);
  while (  TRUE  ) {
    if (  n_width + m_width + dots_width > area_width  ) break;
    if (  n <= m  ) break; // keep my sanity check (WTF), it should never happen 'cause of the above line

    //  Here are extra 'swap turn' conditions
    if (  style == 3  &&  (!(n & 1))  )
      fromleft = (!fromleft);
    else if (  style < 2  )
      fromleft = (!fromleft); // (1)'disables' turn swapping for styles 0, 1

    if (  fromleft  ) {
      pdc->GetCharWidth(*(s+n-1), *(s+n-1), &tmpwidth);
      n_width += tmpwidth;
      n--;
    }
    else {
      pdc->GetCharWidth(*(s+m-1), *(s+m-1), &tmpwidth);
      m_width += tmpwidth;
      m++;
    }

    fromleft = (!fromleft); // (1)
  }

  if ( fromleft ) m--; else n++;

  // Final steps
  // 1. CString version
  CString*  abbr = new CString;
  abbr->Format("%*.*s...%*.*s", m-1, m-1, s, len-n, len-n, s + n);
  return abbr;

  /* 2. char* version, if you dont want to use CString (efficiency), replace CString with char*,
                       new CString with _strdup("") and use this code for the final steps:

  char* abbr = (char*)malloc(m + (len-n) + 3 +1);
  strncpy(abbr, s, m-1);
  strcpy(abbr + (m-1), "...");
  strncpy(abbr+ (m-1) + 3, s + n, len-n);
  abbr[(m-1) + (len-n) + 3] = 0;
  return abbr;
  */
}

Se si desidera solo il formato puntini di sospensione "standard", ( "Ciao ...") è possibile utilizzare il DrawText (o il equivalient MFC funzione ) la funzione di passaggio DT_END_ELLIPSIS.

Scopri anche DT_WORD_ELLIPSIS (tronca qualsiasi parola che non rientra nel rettangolo e aggiunge ellissi) o DT_PATH_ELLIPSIS (quello che fa Explorer per visualizzare i percorsi lunghi).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top