Учитывая последовательность символов Юникода, как я могу получить строку символов пробела, которая имеет одинаковую ширину (по крайней мере, в моноширинных шрифтах, которые отображают каждый символ с одинарной или двойной шириной символов из Базовая латиница )
Примеры
Например, задана строка `\ u0061 \ u0020 \ u0020 \ u0063 'с пятью символами, которая выглядит следующим образом:
a b c
('a', пробел, 'b', пробел, 'c'), я хотел бы получить строку, состоящую всего из пяти пробелов:
\u0020\u0020\u0020\u0020\u0020
и дано \u6b22\u8fce\u5149\u4e34
, которое выглядит как
欢迎光临
Я бы хотел получить строку, содержащую четыре идеографических пробела: \u3000\u3000\u3000\u3000
.
Фон
Вот пример, где это имеет значение: отчеты об ошибках в компиляторах для языков, которые поддерживают Unicode. Предположим, что у нас есть некоторый гипотетический язык программирования PL (может быть Python, Java, Scala, Ruby ...), который имеет строковые литералы и круглые скобки. Предположим, что это недопустимый фрагмент кода с кодом PL , поскольку он содержит несопоставленные скобки:
"stringLiteral")
Если бы мы попытались скомпилировать его, компилятор PL может выдать сообщение об ошибке, которое выглядит следующим образом:
:1: error: ';' expected but ')' found.
"stringLiteral")
^
Обратите внимание на «фантомную строку», за которой следует '^'
в последней строке: она точно указывает на непревзойденную закрывающую скобку.
Если я попробую то же самое с символами CJK, вот что я получу:
:1: error: ';' expected but ')' found.
"欢迎光临欢迎光临欢迎光临欢迎光临欢迎光临欢迎")
^
Обратите внимание, что теперь "фантомная строка" в последней строке состоит из обычных латинских пробелов, а в консоли '^'
выглядит так, как будто она находится где-то посередине строки символов CJK, а не в скобка.
Если я попробую то же самое с хорватскими символами:
:1: error: ';' expected but ')' found.
"DŽDždžLJLjljNJNjnj")
^
указатель '^'
также оказывается, казалось бы, в совершенно неправильном положении, потому что эти специальные хорватские символы намного шире обычных пробелов.
Все примеры дают похожие результаты в таких языках, как Python, Java, Scala, Ruby (просто скопируйте-вставьте " y⃝e҈s҉ ")
или "临欢迎光临欢迎")
в интерактивную оболочку и посмотрите, чем заканчивается ^
).
Попытка решения
Вот наивная попытка генерировать "фантомные" строки в Scala. Есть метод Character.isIdeographic
. Я могу использовать его для определения метода phantom
, сопоставляя каждый идеографический символ с \u3000
, а все остальные символы с ' '
(обычный пробел).
def phantom(s: String) =
s.map(c => if (Character.isIdeographic(c)) '\u3000' else ' ')
В простых случаях это работает. Например, если я определю строку
val s = "foo欢迎光临欢迎bar光临欢baz"
и затем выведите строку, за которой следует вертикальная черта |
, разрыв строки, а затем phantom(s)
, за которой следует вертикальная черта |
,
println(s + "|\n" + phantom(s) + "|")
тогда получаю:
foo欢迎光临欢迎bar光临欢baz|
|
и вертикальные полосы в конце строк идеально выстраиваются, потому что phantom(s)
теперь
\u0020\u0020\u0020\u3000\u3000\u3000\u3000\u3000\u3000\u0020\u0020\u0020\u3000\u3000\u3000\u0020\u0020\u0020
то есть:
- три обычных пробела, соответствующих "foo"
- шесть идеографических пространств, соответствующих пьесе "欢迎 光临 欢迎"
- затем снова три пробела, соответствующих "bar"
- ...
и т. Д.
Однако, если я попробую то же самое с хорватскими символами, я снова получу беспорядок:
DŽDždžLJLjljNJNjnj|
|
(вертикальные полосы не совпадают).
Вопрос
Определяет ли Unicode какие-либо свойства, которые позволили бы мне генерировать надежные «фантомные» строки одинаковой ширины?