Я уверен, что все мы видели многоточие в статусах Facebook (или в другом месте), и нажал «Показать больше», и осталось только еще 2 символа или около того. Я предполагаю, что это из-за ленивого программирования, потому что, безусловно, есть идеальный метод.
Мой считает тонких символов [iIl1]
как «полусимволы», но это не обходит многоточие » выглядит глупо, когда они скрывают едва ли каких-либо персонажей.
Есть ли идеальный метод? Вот мое:
/**
* Return a string with a maximum length of <code>length</code> characters.
* If there are more than <code>length</code> characters, then string ends with an ellipsis ("...").
*
* @param text
* @param length
* @return
*/
public static String ellipsis(final String text, int length)
{
// The letters [iIl1] are slim enough to only count as half a character.
length += Math.ceil(text.replaceAll("[^iIl]", "").length() / 2.0d);
if (text.length() > length)
{
return text.substring(0, length - 3) + "...";
}
return text;
}
Язык на самом деле не имеет значения, но помечен как Java, потому что это то, что мне больше всего интересно видеть.
Похоже, вы могли бы получить более точную геометрию из графического контекста Java FontMetrics
.
Приложение: При подходе к этой проблеме может помочь различие между моделью и представлением. Модель представляет собой String
, конечную последовательность кодовых точек UTF-16, а представление представляет собой серию глифов, отображаемых некоторым шрифтом на некотором устройстве.
В частном случае Java можно использовать SwingUtilities.layoutCompoundLabel()
для выполнения перевода. В приведенном ниже примере перехватывается вызов макета в BasicLabelUI
, чтобы продемонстрировать эффект. Может быть возможно использовать метод полезности в других контекстах, но соответствующие FontMetrics
должны быть определены эмпирически.
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.plaf.basic.BasicLabelUI;
/** @see http://stackoverflow.com/questions/3597550 */
public class LayoutTest extends JPanel {
private static final String text =
"A damsel with a dulcimer in a vision once I saw.";
private final JLabel sizeLabel = new JLabel();
private final JLabel textLabel = new JLabel(text);
private final MyLabelUI myUI = new MyLabelUI();
public LayoutTest() {
super(new GridLayout(0, 1));
this.setBorder(BorderFactory.createCompoundBorder(
new LineBorder(Color.blue), new EmptyBorder(5, 5, 5, 5)));
textLabel.setUI(myUI);
textLabel.setFont(new Font("Serif", Font.ITALIC, 24));
this.add(sizeLabel);
this.add(textLabel);
this.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
sizeLabel.setText(
"Before: " + myUI.before + " after: " + myUI.after);
}
});
}
private static class MyLabelUI extends BasicLabelUI {
int before, after;
@Override
protected String layoutCL(
JLabel label, FontMetrics fontMetrics, String text, Icon icon,
Rectangle viewR, Rectangle iconR, Rectangle textR) {
before = text.length();
String s = super.layoutCL(
label, fontMetrics, text, icon, viewR, iconR, textR);
after = s.length();
System.out.println(s);
return s;
}
}
private void display() {
JFrame f = new JFrame("LayoutTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new LayoutTest().display();
}
});
}
}