Постоянный массив из набора

У меня есть следующий код для создания надстрочных версий цифр от «0» до «9» и знаков «+» и «-».

const
  Digits = ['0' .. '9'];
  Signs = ['+', '-'];
  DigitsAndSigns = Digits + Signs;

function SuperScript(c: Char): Char;
{ Returns the superscript version of the character c
  Only for the numbers 0..9 and the signs +, - }
const
  SuperDigits: array ['0' .. '9'] of Char = ('⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹');
begin
  if CharInSet(c, Digits) then
    Result := SuperDigits[c]
  else if c = '+' then
    Result := '⁺'
  else if c = '-' then
    Result := '⁻'
  else
    Result := c;
end;

Это работает, но не очень элегантно. В идеале я хотел бы иметь что-то вроде

  SuperDigits: array [DigitsAndSigns] of Char = ('⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹', '⁺', '⁻');

Но это даже не компилируется.

Можно ли как-то создать и установить элемент массива для каждого элемента в наборе?

Я знаю, что мог бы использовать более тяжелые компоненты, такие как TDictionary, но (если возможно) я хотел бы использовать наборы или перечисления.

Интересно, почему вы не продолжите с else if CharInSet(c, Signs) then Result := SuperSigns[c], а настаиваете на одиночных if. Также с точки зрения производительности case c of было бы лучше.

AmigoJack 15.02.2023 23:14
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Веб-скрейпинг, как мы все знаем, это дисциплина, которая развивается с течением времени. Появляются все более сложные средства борьбы с ботами, а...
Калькулятор CGPA 12 для семестра
Калькулятор CGPA 12 для семестра
Чтобы запустить этот код и рассчитать CGPA, необходимо сохранить код как HTML-файл, а затем открыть его в веб-браузере. Для этого выполните следующие...
ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023
ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023
О тренинге HTML JavaScript :HTML (язык гипертекстовой разметки) и CSS (каскадные таблицы стилей) - две основные технологии для создания веб-страниц....
Как собрать/развернуть часть вашего приложения Angular
Как собрать/развернуть часть вашего приложения Angular
Вам когда-нибудь требовалось собрать/развернуть только часть вашего приложения Angular или, возможно, скрыть некоторые маршруты в определенных средах?
Запуск PHP на IIS без использования программы установки веб-платформы
Запуск PHP на IIS без использования программы установки веб-платформы
Установщик веб-платформы, предлагаемый компанией Microsoft, перестанет работать 31 декабря 2022 года. Его закрытие привело к тому, что мы не можем...
Оптимизация React Context шаг за шагом в 4 примерах
Оптимизация React Context шаг за шагом в 4 примерах
При использовании компонентов React в сочетании с Context вы можете оптимизировать рендеринг, обернув ваш компонент React в React.memo сразу после...
2
1
94
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Можно ли как-то создать и установить элемент массива для каждого элемента в наборе?

Нет.

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

В вашем случае Digits + Signs — это то же самое, что и Signs + Digits, так как же вы могли знать, в каком порядке перечислять элементы?

Кроме того, возможно, стоит указать, что скобки в

const
  Digits = ['0' .. '9'];

Не того же вида, что и скобки в

array ['0' .. '9'] of Char 

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

Теоретически вы можете создать перечисляемый тип с вашими символами, но тогда вам нужно преобразовать входной символ в перечисляемый тип, а затем обратно в отображаемый символ. Так что это не удобно.

В вашем конкретном случае у вас есть отображение Char → Char. Базовые кодовые точки Unicode на самом деле недостаточно хороши, чтобы облегчить любые умные трюки (например, вы можете сделать с строчными буквами ASCII -> верхний регистр). На самом деле цифры надстрочного индекса даже не идут подряд! Таким образом, у вас нет другого выбора, кроме как сделать какое-то простое сопоставление на основе данных.

Я бы просто использовал конструкцию case , как в UnicodeSuperscript здесь :


function UnicodeSuperscript(const C: Char): Char;
begin
  case C of
    '0':
      Result := '⁰';
    '1':
      Result := '¹';
    '2':
      Result := '²';
    '3':
      Result := '³';
    '4':
      Result := '⁴';
    '5':
      Result := '⁵';
    '6':
      Result := '⁶';
    '7':
      Result := '⁷';
    '8':
      Result := '⁸';
    '9':
      Result := '⁹';
    '+':
      Result := '⁺';
    '-', '−':
      Result := '⁻';
  else
    Result := C;
  end;
end;

С точки зрения элегантности, я думаю, вы можете захотеть отделить данные от логики. Один (избыточный и более медленный!) Подход состоял бы в том, чтобы хранить постоянный массив, как в

function UnicodeSuperscript(const C: Char): Char;
const
  Chars: array[0..12] of
    record
      B,
      S: Char
    end
    =
    (
      (B: '0'; S: '⁰'),
      (B: '1'; S: '¹'),
      (B: '2'; S: '²'),
      (B: '3'; S: '³'),
      (B: '4'; S: '⁴'),
      (B: '5'; S: '⁵'),
      (B: '6'; S: '⁶'),
      (B: '7'; S: '⁷'),
      (B: '8'; S: '⁸'),
      (B: '9'; S: '⁹'),
      (B: '+'; S: '⁺'),
      (B: '-'; S: '⁻'),
      (B: '−'; S: '⁻')
    );
begin
  for var X in Chars do
    if C = X.B then
      Exit(X.S);
  Result := C;
end;
Ответ принят как подходящий

На самом деле есть решение для достижения того, чего вы хотите, но, возможно, не того, чего вы ожидали:

type
  SuperDigit = record
  private
    class function GetItem(const C: Char): Char; static;
  public
    class property Item[const C: Char]: Char read GetItem; default;
  end;

class function SuperDigit.GetItem(const C: Char): Char;
const
  cDigitsAndSigns = '0123456789+-';
  cSuperScripts   = '⁰¹²³⁴⁵⁶⁷⁸⁹⁺⁻';
begin
  Result := C;
  var idx := Pos(C, cDigitsAndSigns);
  if idx >= 0 then
    Result := cSuperScripts[idx];
end;

С помощью этого объявления вы можете написать что-то вроде этого:

procedure ToSuperScript(var S: string);
begin
  for var I := 1 to Length(S) do
    S[I] := SuperDigit[S[I]];
end;

Преимущество этого способа в том, что cDigitsAndSigns также может быть таким же гибким, как = Digits + Signs, объединяя несколько строк по желанию.

AmigoJack 16.02.2023 00:38

Это очень близко к тому, что я хочу. С точки зрения производительности решение Андреаса с использованием case ... может быть лучше, но для небольших наборов это очень элегантное решение.

Matej 16.02.2023 09:50

Дело требует столько сравнений, сколько поз. Сомневаюсь, что разницу в производительности можно измерить, не говоря уже о том, чтобы заметить. Если производительность является ключевым фактором, вы должны рассмотреть ассемблер или таблицу поиска.

Uwe Raabe 16.02.2023 11:05

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