Идеальный метод для усечения строки с многоточием

Я уверен, что все мы видели многоточие в статусах 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, потому что это то, что мне больше всего интересно видеть.

56
задан Amy B 30 August 2010 в 02:46
поделиться

1 ответ

Похоже, вы могли бы получить более точную геометрию из графического контекста Java FontMetrics .

Приложение: При подходе к этой проблеме может помочь различие между моделью и представлением. Модель представляет собой String, конечную последовательность кодовых точек UTF-16, а представление представляет собой серию глифов, отображаемых некоторым шрифтом на некотором устройстве.

В частном случае Java можно использовать SwingUtilities.layoutCompoundLabel() для выполнения перевода. В приведенном ниже примере перехватывается вызов макета в BasicLabelUI , чтобы продемонстрировать эффект. Может быть возможно использовать метод полезности в других контекстах, но соответствующие FontMetrics должны быть определены эмпирически.

alt text

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();
            }
        });
    }
}
27
ответ дан 26 November 2019 в 17:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: