【问题标题】:How to check if a string contains only numbers in Postscript如何检查字符串是否仅包含 Postscript 中的数字
【发布时间】:2020-11-23 12:46:09
【问题描述】:

我正在努力研究如何轻松地检查 Postscript 中的字符串,例如 (123456) 只包含数字。例如0,1,2,3,4,5,6,7,8 或 9。

例如:

(1235) isnum 应该将 true 放入堆栈

(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) isnumber ==> true 在栈上

或者有更快的程序吗?

【问题讨论】:

    标签: string numbers compare postscript


    【解决方案1】:

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

    所以,如果你可以使用getinterval将字符一个一个剥掉,做成length=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
    

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

    /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 隐式地对字符串内容进行循环以完成它们的工作。

    【讨论】:

      【解决方案2】:

      这是一个可以自定义的程序片段。这将检查字符串中的每个字符是否为数字。字符串中的数字是从 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
      

      EDIT2:这可以满足您的要求。如果我知道的话,可能会有更简单的方法。

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

      EDIT3:感谢 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
      

      EDIT5:再次感谢 luser droog 提供让我真正思考的线索。对于零长度字符串,这仍然在堆栈上为真:

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

      EDIT6:再次感谢您提供有关已停止和其余部分的信息。这很有帮助。我需要更多的时间来学习和实验。

      我添加了一个测试,以防运算符用于字符串以外的东西,因此对于数组之类的东西返回 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
      

      EDIT7:最后。这也有效。

      /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
      

      【讨论】:

      • 好东西。您可能想调查stopped。像{ { ... } loop } stopped 这样的东西会让你调用stop 来跳出循环,stopped 会产生一个布尔值,让你知道是否调用了`stop`。另外,请参阅我的答案以了解另一种方法。
      • 在我的回答中添加了stopped 的示例。
      • 有关stopped 的一些示例和说明,请参阅this post of mine,其中包含为 SO 的文档项目编写的材料。这是理解和使用 PS 中的错误处理的关键。
      • 对于“EDIT5”代码,您可以轻松添加零长度检查。只需将结果用于初始布尔值true。 IE。 { dup length 0 ne exch { dup...} forall }
      • 我添加了一个 EDIT6,同时添加了停止和长度检查。今晚没时间了。
      【解决方案3】:

      这听起来像是 map-reduce 策略的工作。对于基本情况,检查一个字符:

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

      然后,我们可以用这个过程在字符串上做一个映射。

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

      这会产生一个布尔数组,字符串的每个字符对应一个。要将这个数组折叠成一个布尔值,我们可以reduce使用初始元素和二元运算的数组。

      /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 循环并消除布尔数组来提高效率。但是此代码没有在初学者 6789 的答案中表现出的早期退出行为。

      /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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-12-19
        • 1970-01-01
        • 1970-01-01
        • 2014-06-04
        • 1970-01-01
        • 2011-04-04
        • 1970-01-01
        相关资源
        最近更新 更多