Voglio adattarsi alle stringhe in una larghezza specifica. Esempio "Hello world" -> "... world", "Hello ...", "He ... rld".
Sai dove posso trovare il codice per questo? È un trucco accurato, molto utile per rappresentare le informazioni, e mi piacerebbe aggiungerlo nelle mie applicazioni (ovviamente).
Modifica: Mi dispiace, ho dimenticato di menzionare il Font parte. Non solo per stringhe di larghezza fissa ma in base al carattere.Come posso trasformare una stringa in una forma abbreviata?
risposta
Si tratta di 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 sarebbe:
theString = "..." + theString.Right(desiredWidth-3);
o se si vuole che nel mezzo:
theString = theString.Left((desiredWidth-3)/2) + "..." + theString.Right((desiredWidth-3)/2 + ((desiredWidth-3) mod 2))
Modifica:
Suppongo che tu stia utilizzando MFC. Dal momento che lo desideri con i font, puoi utilizzare la funzione CDC::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 una ricerca intelligente quanto vuoi - ad esempio, potresti provare "Hello Worl ..." e poi "Hello Wor ..." e poi "Hello Wo ..."; rimuovendo un personaggio finché non lo trovi adatto. In alternativa, puoi fare un binary search - prova "Hello Worl ..." - se non funziona, usa solo metà dei caratteri del testo originale: "Ciao ..." - se ciò si adatta, prova a metà strada tra e: "Ciao Wo ..." fino a trovare il più lungo che si adatta ancora. Oppure si potrebbe provare alcuni 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;
}
Sì, il suo MFC e io implementeremo un adattamento * intelligente *. Volevo vedere se c'è un'implementazione efficiente per quel tipo di cose prima di provare a implementare la mia. Ma immagino di dover sedermi ed essere creativo :) –
Risposta fantastica, completa, utile. –
Grazie, Aidan :-) – Smashery
È davvero piuttosto banale; Non penso che troverai codice specifico a meno che tu non abbia qualcosa di più strutturato in mente.
Che, fondamentalmente, vogliono:
- per ottenere la lunghezza della stringa che hai, e la larghezza della finestra.
- calcola quanti caratteri puoi ricavare dalla stringa originale, che in pratica sarà la larghezza della finestra-3. Chiama che k.
- A seconda che si desideri posizionare i puntini di sospensione al centro o all'estremità destra, prendere i caratteri del primo piano (k/2) da un'estremità, concatenati con "...", quindi concatenati con l'ultimo floor (k/2) caratteri (con possibilmente un altro carattere necessario a causa della divisione); o prendi i primi k caratteri, seguiti da "...".
penso La risposta di Smashery è un buon inizio.Un modo per arrivare al risultato finale sarebbe scrivere un codice di test con alcuni input di test e output desiderati. Una volta che hai un buon set di setup di test, puoi implementare il tuo codice di manipolazione delle stringhe fino a quando non passi tutti i tuoi test.
- 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 primo:
ellipseWidth = calcolare la larghezza (...)
Rimuovere la parte stringa con larghezza ellipseWidth dalla fine e aggiungere ellisse.
qualcosa di simile: Ciao ...
Probabilmente troverai che larghezza (testo) + larghezza (ellissi) non è uguale alla larghezza (testo + puntini di sospensione). Questo perché alcuni glifi si sovrappongono quando vengono renderizzati per renderlo più bello. Quindi non puoi semplicemente sottrarre la larghezza ellittica dalla larghezza desiderata - devi controllare l'intera lunghezza (tra cui ellissi) – Smashery
Sì, è corretto. In un ciclo dobbiamo verificare se la dimensione con l'ellisse corrisponde alla dimensione data (per identificare i caratteri da rimuovere dalla stringa). –
Per coloro che sono interessati per una routine completa, questa è la mia 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;
*/
}
+1 Bel lavoro! Solo una parola di cautela: ho scoperto quando si faceva una cosa simile in un'altra lingua che quando si combinano le lettere in un font, potrebbero non essere necessariamente uguali alla somma delle singole lunghezze. Ad esempio, quando si posiziona "W" accanto a "A", il renderer dei caratteri potrebbe avvicinarli un po 'per renderlo più bello all'occhio umano. Quindi larghezza ('W') + larghezza ('A') potrebbe non essere uguale alla larghezza ('WA'). Per le stringhe piccole, probabilmente farà la differenza solo di alcuni pixel, ma per quelli più lunghi, potrebbe essere abbastanza evidente. – Smashery
Grazie. Ok, lo controllerò. –
Anche grazie per suggerire la ricerca binaria nella tua risposta, ottima idea! Forse lo implementerò quando avrò tempo - la ricerca binaria può essere complicata quindi l'ho saltata nella prima versione :) –
Se si desidera solo la "standard" formato ellissi, ("Ciao ...") è possibile utilizzare la funzione DrawText (o equivalient MFC function) che passa DT_END_ELLIPSIS
.
Controllare anche DT_WORD_ELLIPSIS
(tronca qualsiasi parola che non rientra nel rettangolo e aggiunge ellissi) o DT_PATH_ELLIPSIS
(quale Explorer esegue per visualizzare percorsi lunghi).
Penso di aver bisogno di un algoritmo quando ho postato la domanda, ma grazie comunque, è super conveniente! –
Ho trovato la tua domanda cercando lo stesso problema, ho cercato su MSDN GetTextExtent e ho trovato questa semplice opzione in DrawText. Dal momento che avevo bisogno di puntini di sospensione alla fine, per me era abbastanza, e forse per alcuni futuri lettori sarà anche abbastanza! –
sì, questo è il modo di farlo se usiamo GDI e abbiamo bisogno di un ritocco di testo di base. –
- 1. Come posso trasformare una stringa in una lista in Python?
- 2. come trasformare una stringa in un'espressione linq?
- 3. Come trasformare una stringa in una chiamata di funzione JavaScript?
- 4. Codifica di una stringa numerica in una stringa alfanumerica abbreviata e di nuovo indietro
- 5. Come trasformare una stringa in minuscolo con preg_replace
- 6. Come trasformare una NSString in NSDate?
- 7. Come posso tagliare una forma dentro un'altra?
- 8. Python-equivalente di forma abbreviata "se" in C++
- 9. d3.js - mostra grandi numeri sull'asse in forma abbreviata
- 10. Come posso trasformare una bitmap in un Uri?
- 11. È già presente una stringa in una normale forma di compatibilità nella corrispondente forma canonica normale?
- 12. Trasformare un hash in una stringa di coppie nome-valore
- 13. Posso trasformare una stringa in un blocco di codice in swift?
- 14. Come posso modificare la forma di una variabile in TensorFlow?
- 15. Come posso aggiungere una stringa formattata a una stringa esistente?
- 16. Come posso trasformare un file .properties durante una build Gradle?
- 17. Come posso racchiudere una stringa in Perl?
- 18. Come posso rilevare "_" in una stringa C++?
- 19. Come posso inserire virgolette in una stringa?
- 20. Come posso troncare una stringa in jQuery?
- 21. Come posso tagliare una stringa in C?
- 22. Come posso sostituire una stringa in Netbeans?
- 23. Come posso convertire una stringa in jsx?
- 24. Come trasformare CBUUID nella stringa
- 25. Come crei una forma dinamica in Django?
- 26. Come trasformare una riga dataframe panda in una stringa separata da virgola
- 27. Trasformare una virgoletta singola in una virgoletta sfuggita all'interno di una stringa
- 28. Come trasformare una raccolta mutevole in una immutabile
- 29. come costruire una forma trapezoidale in Android?
- 30. Python - Trasformare l'input dell'utente in una lista
Stai utilizzando MFC o ...? – Smashery