Как я могу распечатать контент в середине экрана в Rust?

Во-первых, я пробовал использовать множество библиотек, и ни одна из них, похоже, не работала должным образом, я тоже установил ширину терминала вручную, и текст все тот же, он не в центре терминала, кто-нибудь, что мне следует сделать?

ОБС: Я обнаружил, это из-за цветов, но как напечатать по центру и с цветами? (без цветов все идет правильно, вот как я обнаружил)

fn print_centered(content: &str) {
    let term_size = crossterm::terminal::size();
    let term_width = term_size.unwrap_or((80, 24)).0 as usize;

    println!("{: ^term_width$}", content);
}

Я пробовал вручную и с большим количеством ящиков, но не отцентрировал содержимое должным образом, как ожидалось.

В чем ваша проблема: 1. Размер терминала указан неправильно; или 2. текст не центрирован, несмотря на правильный размер?

jthulhu 30.04.2024 18:02

Размер терминала указан правильно, поскольку я проверял его вручную, но при печати текста он не находится в центре, как вы можете видеть на изображении.

mi66 mc 30.04.2024 18:03

Если вы также печатаете цветовые коды ANSI, они могут смещать текст относительно центра, если они не симметричны вокруг текста, как и символы Юникода с несколькими кодовыми точками.

BallpointBen 30.04.2024 18:08

вот и все, но как мне распечатать его в центре цветами?

mi66 mc 30.04.2024 18:15

Трудно сказать по изображению, но код кажется очень разумным. Я бы, вероятно, заменил пробел каким-нибудь печатным символом, например. println!("{:~^term_width$}", content); а потом посчитайте. Сколько всего символов напечатано? Соответствует ли это выводу tput cols?

ChrisB 30.04.2024 19:20

я думаю, он не соответствует term_width из-за цветов

mi66 mc 01.05.2024 00:33

@mi66mc: Понятно, в этом есть смысл. Строка формата Rust выдаст вам term_width символы Юникода, независимо от их отображаемого размера. Если вы включите escape-последовательности Ansi в content (которые состоят из нескольких символов, но не отображаются), отображаемая длина будет слишком короткой. Вы можете использовать такую ​​библиотеку, как ansi parser, для перебора content и определения фактической длины текста или, в качестве альтернативы, просто определить длину перед добавлением escape-символов ansii.

ChrisB 01.05.2024 01:26

Если вы нашли ответ, пожалуйста, опубликуйте его, ведь собрать кучу пар QA — это весь смысл Stack Overflow.

cafce25 01.05.2024 15:36
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
2
8
121
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

На решение в целом намекнули в комментариях. Итак, это кульминация всего этого, а также фактическое решение.

Как вы уже поняли, проблема в том, что стандартное форматирование заливки/выравнивания основано на символах. Таким образом, встраивание цветовых кодов ANSI в строку считается символами.

Это можно наблюдать с помощью следующего кода:

let width = 25;
let text = "Hello World";
let text2 = format!("\x1b[94m{}\x1b[39m", text);

println!("{:-^width$}", "");
println!("{:-^width$}", text);
println!("{:-^width$}", text2);

println!();
println!("{} characters", text.chars().count());
println!("{} characters", text2.chars().count());

Какие выходы:

Использование изображения, поскольку вывод цветной.


Простой обходной путь — использовать контейнер консоли , который предоставляет различные утилиты для измерения текста, заполнения, усечения и т. д. При учете кодов ANSI:

Вы даже можете использовать Term . size(), чтобы получить ширину терминала.

Чтобы центрировать строку, содержащую коды ANSI, вам следует использовать pad_str() :

use console::{pad_str, Alignment};

let width = 25;
let text = "Hello World";
let text2 = format!("\x1b[94m{}\x1b[39m", text);

let text = pad_str(text, width, Alignment::Center, None);
let text2 = pad_str(&text2, width, Alignment::Center, None);

println!("{:-^width$}", "");
println!("{text}");
println!("{text2}");
println!("{:-^width$}", "");

Какие выходы:


Опять же, pad_str() не ломается text, даже если он усечен. Например, давайте установим width на 6 и будем использовать (многоточие) для усечения.

use console::{pad_str, Alignment};

const ELLIPSIS: &str = "\u{2026}";

let width = 6;
let text = "Hello World";
let text2 = format!("\x1b[94m{}\x1b[39m", text);

let text = pad_str(text, width, Alignment::Center, Some(ELLIPSIS));
let text2 = pad_str(&text2, width, Alignment::Center, Some(ELLIPSIS));

println!("{:-^width$}", "");
println!("{text}");
println!("{text2}");
println!("{:-^width$}", "");

Что правильно выводит:

Другие вопросы по теме