任何优雅的方式来定义字母数字子类型?

时间:2017-11-30 23:19:30

标签: string character ada

这是我在本网站上的第一个问题。我总是设法找到一些与我有类似问题的人回答的问题,但这次似乎没有。

所以在这里,我试图生成大量相对较短的字符串作为ID号,但希望它们只包含字母数字字符。

我尝试了一些类似的事情:

subtype Char is character range 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9';

添加括号,逗号,创建新类型而不是子类型。

我知道我可以枚举我想要的所有角色,但我可以让自己完成这样一个愚蠢的任务,就像在枚举类型中编写每个62个字符一样。

有没有办法将不同的区间连接成一个子类型?

编辑:所以这是我的代码:

with ada.text_io, ada.integer_text_io, ada.float_text_io, ada.numerics.discrete_random;
use  ada.text_io, ada.integer_text_io, ada.float_text_io;

procedure randomID is

Subtype AlphaNumeric is character 
with dynamic_predicate => AlphaNumeric in 'a'..'z' |
                                          'A'..'Z' |
                                          '1'..'9' ;
package CharGen is new ada.numerics.discrete_random (Alphanumeric);
CharG: CharGen.generator;
id: string (1..5);

begin
    for i in 1..5 loop
        CharGen.Reset(CharG);
        id(i) := charGen.random(CharG);
    end loop;
end randomID;

但我得到(无论我使用静态还是动态指示)这些错误:

  

09:警告:在a-nudira.adb的实例化中:54
  09:警告:输入" Result_Subtype"有谓词,属性"第一"不允许的   09:警告:将在运行时提出Program_Error   09:警告:在a-nudira.adb的实例化中:54
  09:警告:表达式未通过谓词检查" Result_Subtype"
  09:警告:在s-rannum.ads:86实例化   09:警告:在a-nudira.adb的实例化中:53
  09:警告:输入" Result_Subtype"有谓词,属性"最后"不允许的   09:警告:在s-rannum.adb的实例化中:395
  09:警告:在a-nudira.adb的实例化中:53
  09:警告:输入" Result_Subtype"有谓词,属性"最后"不允许

我理解Ada.numerics生成随机项目的方式与我的类型的性质存在冲突。有办法解决这个问题吗?

3 个答案:

答案 0 :(得分:3)

你可以通过至少两种不同的方式来做到这一点。

使用静态谓词作为+-------------------+----+----+ |timestamp |1 |2 | +-------------------+----+----+ |2017-11-01 05:33:00|5 |null| |2017-11-01 05:32:00|4 |109 | |2017-12-01 05:31:00|6 |111 | |2016-12-01 05:30:00|5 |100 | |2016-12-01 05:34:00|null|95 | +-------------------+----+----+ 的子类型:

Character

作为一种合适的类型:

subtype Alphanumeric_Character is Character
  with Static_Predicate => Alphanumeric_Character in 'a' .. 'z' |
                                                     'A' .. 'Z' |
                                                     '0' .. '9';

答案 1 :(得分:1)

我终于决定是时候玩谓词了,早在2012年之前就已经了解了我认识的小阿达。

由于具有谓词的子类型覆盖在基础类型上,因此必须进行一些有趣的讨论,以保留基础类型,禁止内容和添加内容......

事实证明,某些谓词(例如'first, 'last, 'range)是被禁止的,而您在a-nudira.adb又名ada.numerics.discrete_random中使用了这些谓词。有'first_valid, 'last_valid形式的替换可以按预期工作,但不会'range,这将允许数据类型中的漏洞。

其他一些像'pos, 'val, 'pred,'succ这样的人生存但是他们引用了基础类型,所以AlphaNumeric'Pred('A')是' @'而不是' 9'例如。这很不方便,但是......

谓词的本质不是提供一些处理数组寻址中的漏洞的神奇编程,而是允许按合同编程。

合同编程的本质是双方(来电者和被叫者,实例者和通用包)都必须遵守合同。

不幸的是,ada.numerics.discrete_random并未遵守合同。有可能写一个替代品,但这将是一个比我们现在需要的更大的项目。 (OTOH,如果您正在使用Gnat Pro,您的支持合同可能会涵盖此类增强功能: - )

所以这是一个修改,使用了一个符合合同的包装函数random ......

with ada.text_io, ada.integer_text_io, ada.float_text_io, 
ada.numerics.discrete_random;
use  ada.text_io, ada.integer_text_io, ada.float_text_io;

procedure randomID is

pragma Assertion_Policy(Check);

Subtype AlphaNumeric is character 
with dynamic_predicate => AlphaNumeric in 'a'..'z' |
                                          'A'..'Z' |
                                          '1'..'9' ;

package CharGen is new ada.numerics.discrete_random (character);
CharG: CharGen.generator;

id : string (1..5);

    function random return AlphaNumeric is
    ch : character;
    begin
        loop
           ch := charGen.random(CharG);
           exit when ch in AlphaNumeric;
        end loop;
        return ch;
    end random;

begin
    for i in 1..5 loop
        CharGen.Reset(CharG); -- wait what? should be outside the loop
        id(i) := random;
    end loop;
    put_line(id);
end randomID;

这是否比定义自己的枚举更好,我不能说。但是,该枚举的数组将与字符串不兼容,因此如果您走这条路,您还可以使用其他形式的包装器进行编写。我遇到了这个问题,只需要id array (1 .. 5) of AlphaNumeric,这样可以确保调用者也执行合同。

答案 2 :(得分:0)

好的,所以我决定顺其自然。 这很难看,但无论如何它都会被隐藏起来,所以我并不在乎; Brian Dumond的选择很好,但我不喜欢它必须产生随机字符的事实,直到他们幸运地是字母数字。

procedure randomID is

Type Table is array (1..62) of character;
AlphaNumeric : Table := ('a','b','c'...'7','8','9');
Type Int is new integer range 1..62;
package intGen is new ada.numerics.discrete_random (Int);
intG: IntGen.generator;
id: string (1..5);

begin
    for i in 1..5 loop
        intGen.Reset(intG);
        id(i) := Alphanumeric(integer(intGen.Random(intG)));
    end loop;
end randomID;