英文:
Constant array from set
问题
我有以下用于创建数字'0'到'9'和符号'+'和'-'的上标版本的代码
const
Digits = ['0' .. '9'];
Signs = ['+', '-'];
DigitsAndSigns = Digits + Signs;
function SuperScript(c: Char): Char;
{ 返回字符c的上标版本,仅适用于数字0到9和符号+,- }
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,但(如果可能的话)我想使用集合或枚举。
英文:
I have the following code for creating superscript versions of the digits '0' to '9' and the signs '+' and '-'
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;
This works, but is not very elegant. Ideally I would like to have something like
SuperDigits: array [DigitsAndSigns] of Char = ('⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹', '⁺', '⁻');
but this does not even compile.
Is it somehow possible to create and preset an array element for every element in the set?
I am aware that I could use more heavy components like TDictionary, but (if possible) I would like to use sets or enumerations.
答案1
得分: 5
以下是代码的中文翻译:
实际上,有一种方法可以实现你想要的,但也许不是你所期望的:
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;
英文:
Actually there is a solution to achieve what you want, but perhaps not what you expected:
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;
With this declaration your can write something like this:
procedure ToSuperScript(var S: string);
begin
for var I := 1 to Length(S) do
S[I] := SuperDigit[S[I]];
end;
答案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;
英文:
> Is it somehow possible to create and preset an array element for every element in the set?
No.
This is fundamentally impossible because the set is an unordered container.
In your case, Digits + Signs
is exactly the same thing as Signs + Digits
, so how could you possibly know in what order to enumerate the elements?
Also, it might be worth pointing out that the brackets in
const
Digits = ['0' .. '9'];
are not of the same kind as the brackets in
array ['0' .. '9'] of Char
The brackets in Digits
really do make a set, but the static array syntax has nothing to do with sets. A static array is indexed by an ordinal type.
In theory, you could create an enumerated type with your characters, but then you need to convert an input character to your enumerated type, and then back to the mapped character. So this is not convenient.
In your particular case, you have a mapping Char → Char
. The underlying Unicode code points aren't really nice enough to facilitate any clever tricks (like you can do with ASCII lower case -> upper case, for example). In fact, the superscript digits are not even contiguous! So you have no choice but to do a plain, data-based mapping of some sort.
I'd just use a case
construct like in UnicodeSuperscript
here:
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;
In terms of elegance, I guess you may want to separate data from logic. One (overkill and slower!) approach would be to store a constant array like in
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;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论