Как создать «фантомную» строку для строки Unicode, состоящую из пробельных символов одинаковой ширины? - PullRequest
0 голосов
/ 02 сентября 2018

Учитывая последовательность символов Юникода, как я могу получить строку символов пробела, которая имеет одинаковую ширину (по крайней мере, в моноширинных шрифтах, которые отображают каждый символ с одинарной или двойной шириной символов из Базовая латиница )

Примеры

Например, задана строка `\ 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 какие-либо свойства, которые позволили бы мне генерировать надежные «фантомные» строки одинаковой ширины?

...