如何在Postscript中检查字符串是否仅包含数字



我正在努力研究如何舒适地检查Postscript中的字符串是否(123456)仅包含数字。例如 0、1、2、3、4、5、6、7、8 或 9。

所以例如:

(1235) isnum应该在堆栈上实现

(1234a) isnum应该在堆栈上放置 false

(1.234) isnum应该在堆栈上放置 false

我真的必须使用循环来检查每个字符是否在 (0-9) 内部,如下所示:

/integers (0123456789) def
% checks if a char is in (0123456789)
/isnum
{
integers exch search
{ pop pop pop true }
{ pop false }ifelse
}
def
/isnumber {
% [(number),(number)]
length 1 sub        % [(number), length-1]
0 exch              % [(number), 0, length-1]
1 exch              % [(number), 0, 1, length-1]

% [(number), 0, 1, length-1]

dup /numlen exch 1 add def
/counter 0 def

% for(j=0; j<length-1; j++)
{
/j exch def
% [(number)]

dup j 1 getinterval     % [(number), number[j]] 
/char exch def          % [(number)] && char == number[j]   
char isnum {
/counter counter 1 add def
}if

}for

counter numlen eq
{
true
}
{
false
}ifelse
}def

(12345) (12345) 是编号 ==> true 在堆栈上

还是有更快的程序?

还有另一种编写这种代码的风格,它利用了postscript的关系运算符也适用于字符串的事实。

因此,如果您可以使用getinterval逐个剥离字符以制作长度= 1字符串,则可以直接将它们与(0)(9)进行比较。

/isdigit { dup (0) ge exch (9) le and } def

这使得我另一个答案中的"地图"步骤更加复杂。

/foreach { % array/string proc
1 dict begin { /proc /str }{ exch def }forall   % define args
0 1 /str load length 1 sub     % 3 numbers for `for` later
( { //str exch 1 getinterval
//proc exec } )            % template loop body
cvx exec                       % generate loop body from template
end for                        % discard dict then call `for`
} def
/isnumber { true exch { isdigit and } foreach } def

这就引出了另一个想法。如果您正在使用的字符串有合理的最大长度,则可以与零或九进行比较,即。 长度 = 4 的字符串(0000)(9999)

/zeros (000000000) def
/nines (999999999) def
/isnumber { dup zeros 0 2 index length getinterval ge exch
nines 0 2 index length getinterval le and } def

通过这种方式,gele隐式地对字符串内容执行循环以完成其工作。

这是一个准备自定义的程序片段。这将检查字符串中的每个字符是否为数字。字符串中的数字是 48 到 57 之间的整数:

(345fd2) { dup 48 ge exch 57 le and = } forall

这只是一个起点。可以根据需要累积和检查字符串中每个元素的结果。玩得愉快。

编辑:如果字符串未通过测试,这会在堆栈上留下 false,或者如果通过,则什么都没有:

/isnumb {{dup 48 ge exch 57 le and not{false exit}if} forall} def

编辑2:这符合您的要求。如果我知道,可能会有更简单的方法。

/isnumber? { { dup 48 ge exch 57 le and
{/flag true def}{/flag false def exit} ifelse
} forall
flag
} def

编辑3:感谢luser droog提供我学习如何消除标志的代码。任何空字符串都通过测试,所以要小心。仍然看着停止和停止。

/isnumber { true exch
{ dup 48 ge exch 57 le and   % element is digit 
not{pop false exit}if      % element is not digit
} forall
} def

EDIT4:这会在零长度字符串的堆栈上留下 false:

/isnumeric { dup length 0 eq
{ pop false              % false for zero length string
}{
true exch
{dup 48 ge exch 57 le and
not{pop false exit}if   % early exit for non-digit
} forall                % check each element of string
} ifelse
} def

编辑5:再次感谢luser droog提供的线索,让我真正思考。这仍然在零长度字符串的堆栈上保留 true:

/isnum {true exch {dup 48 ge exch 57 le and and}forall } def

编辑6:再次感谢有关停止和其余的信息。这是非常有帮助的。我需要更多的时间来学习和实验。

我添加了一个测试,以防运算符用于字符串以外的内容,因此对数组之类的内容返回 false 而不是抱怨:

/isnums { 
{dup type /stringtype ne {stop} if
dup length 0 ne exch
{dup 48 ge exch 57 le and and}forall
}stopped {pop false}if
} def

编辑7:最后。这也行得通。

/isnumbr { 
{dup type /stringtype ne {pop false stop} if
dup length 0 ne exch
{dup 48 ge exch 57 le and and}forall
}stopped not and
} def

这听起来像是地图缩减策略的工作。对于基本情况,检查一个字符:

/isdigit { dup 48 ge exch 57 le and } def  % int . bool

然后,我们可以在字符串上使用此过程进行映射。

/map { [ 3 1 roll forall ] } def  % string proc . array

这将生成一个布尔数组,字符串的每个字符一个布尔值。要将此数组折叠为单个布尔值,我们可以使用初始元素和二进制操作来减少数组。

/reduce { exch 3 1 roll forall } def  % array initial proc . result

一起:

/isnumber { //isdigit map  true {and} reduce } def  % string . bool
(1234) isnumber

铌。此代码将报告空字符串的true,因为它不包含任何非数字字符。 上面的//isdigit也可以写{isdigit}但使用立即加载的名称可以避免在此处创建新数组。这不能用and来完成,因为它很可能是一个运算符,因此不是forall的兼容类型。

通过组合两个forall循环并消除布尔数组,可以提高效率。但是这段代码没有 beginner6789 的答案中展示的早期退出行为。

/isnumber { true exch { isdigit and } forall } def

编辑:如何使用stopped为此

为了添加早期退出行为,我们可以利用{ ... stop ... } stopped结构,它让我们从循环(或任何代码)的中间解脱出来,并自动提供一个布尔值。

/isnumber { { { isdigit not {stop} if } forall } stopped not } def

或者,使用更清晰的缩进,

/isnumber {
{
{
isdigit not {stop} if      % if any of the individual tests fail, stop
} forall
} stopped                      % yields true if stop was called
not                            % reverse the boolean,
%  so now false==stop was called
} def

类似的操作也可以通过exit和堆栈杂耍来完成。

/isnumber {
true exch
{
isdigit not { pop false exit } if
} forall
} def

相关内容

  • 没有找到相关文章

最新更新