Строка обрезки jruby на основе длины с эллипсами

Это довольно специфическая проблема, но мне интересно, есть ли у кого-нибудь блестящее решение. Я пытаюсь поместить строку с фиксированным размером шрифта в поле произвольного размера, так что, если вся строка не помещается, я хочу обрезать ее и добавить многоточие (...).

Итак, если мой текст «нидерланды», я хочу определить, какая его часть помещается в мою коробку произвольного размера, чтобы она выглядела как «нижняя часть…».

Я использую jruby, так что java или ruby ​​в порядке. Я не могу придумать фантастического решения, кроме обрезки/тестирования char-by-char, чтобы увидеть, подходит ли строка. Поскольку это не шрифт с фиксированной шириной, я не могу просто взять каждый символ одинаковой ширины, что сделало бы это намного проще.

Любые мысли или советы, которые могли бы указать мне в правильном направлении?


person brad    schedule 19.10.2009    source источник
comment
Какую структуру графического интерфейса вы используете?   -  person Pesto    schedule 19.10.2009
comment
каков результат для строки? это как бы имеет большое значение.   -  person Gareth Davis    schedule 19.10.2009
comment
Это приложение для рельсов. Это изображение, которое создается как метка для местоположения на карте. Изображение представляет собой круг, представляющий размер местоположения, ограничительная рамка - это то, что я пытаюсь поместить в строку.   -  person brad    schedule 19.10.2009


Ответы (3)


Посимвольный цикл, вероятно, просто прекрасен. Но если вы делаете их миллиарды и вам нужно их ускорить, вы можете использовать двоичный поиск нужной длины, а не просто перебирать символы. Вот общий метод binary_search, который вы можете вызвать для Integer. Дайте ему блок сравнения ‹=>, который возвращает -x 0 или +x, и он итеративно прыгает на половину каждый раз, пока либо тест не вернет 0, либо размер перехода не станет слишком маленьким.

class Integer
  def binary_search
    current = self
    nextjump = current / 2.0
    until (test = yield(current)) == 0 || nextjump < 0.5
      if test < 0
    current += nextjump
      else
        current -= nextjump
      end
      nextjump /= 2.0
    end
    current
  end
end

Затем используйте его следующим образом:

goal = whatever
a[0...(a.size.binary_search {|i| a[0...i].stringWidth - goal})]
person glenn mcdonald    schedule 19.10.2009
comment
это хорошая идея, я думаю, что пока я придерживаюсь посимвольного, так как я не делаю миллиарды, но я поиграюсь со скоростью, если замечу какие-либо удары по производительности. Спасибо! - person brad; 19.10.2009

Альтернативным подходом может быть обработка усечения отображения в CSS!

<div style="border: 1px solid gray; width: 200px;">
<span style="float: right; color: gray">...</span>
<div style="width: 184px; overflow: hidden; white-space: nowrap">
This is a really long string that goes on and on and on and we need to do something about it eventually but for now it just isn't important so I don't want to think about it.
</div></div>

Это избавляет вас от неблагодарной задачи беспокойства о метриках шрифтов браузеров ваших пользователей (которых вы не знаете, и к которым метрики шрифтов вашего Java-сервера, таким образом, имеют неизвестное отношение).

person glenn mcdonald    schedule 19.10.2009
comment
это справедливое предложение, но я создаю изображение, которое помещается на карту, так что это динамическая вещь, мне нужно, чтобы текст был на изображении, так как сервер просто возвращает изображение на основе параметров ссылки. - person brad; 19.10.2009

взгляните на FontMetrics в Java. класс и, в частности, метод stringWidth.

person Martin DeMello    schedule 19.10.2009
comment
Я уже использую это, чтобы определить, помещается ли строка в поле, но это на самом деле не помогает мне алгоритмически обрезать строку до подмножества символов, если строка не подходит. В настоящее время я зацикливаю char-by-char и тестирую stringWidth. Кажется, слишком много работы - person brad; 19.10.2009
comment
ну, вы могли бы разделить пополам, а не зацикливать символ за символом, но на самом деле, похоже, что вам нужно сделать что-то подобное, чтобы правильно обрезать. если вам нужна хорошая начальная оценка, относитесь ко всему как к фиксированной ширине (через getMaxAdvance) и смотрите, к чему это приведет. или используйте getWidths и выполняйте расчеты самостоятельно в чистом коде без дополнительной привязки к шрифту. - person Martin DeMello; 19.10.2009