如何提取由分隔符分隔的字符串正在开启4gl?

时间:2016-03-28 06:03:05

标签: string loops progress-4gl openedge

我有一个字符串

v-edistring  = "STS++56+202:::DUE TO HOLIDAY1'STS++56+202:::DUE TO HOLIDAY2'STS++56+202:::DUE TO HOLIDAY3'" 

撇号(')表示线的终止,每条线都是一个线段。我已经提取了每个段并将其分配给变量段。

现在对于每个段我需要循环以按顺序查找元素(STS,56,202,DUE TO HOLIDAY1)等。

DEFINE VARIABLE v-edistring  AS CHARACTER   NO-UNDO.
DEFINE VARIABLE v-cnt AS INTEGER     NO-UNDO.
DEFINE VARIABLE segment AS CHARACTER   NO-UNDO.

v-edistring = "STS++56+202:::DUE TO HOLIDAY1'STS++56+202:::DUE TO HOLIDAY2'STS++56+202:::DUE TO HOLIDAY3'".

DO  v-cnt = 1 TO num-entries(v-edistring, "'") - 1  :

    ASSIGN segment = string(entry(v-cnt, v-edistring, "'")).

   MESSAGE segment
       VIEW-AS ALERT-BOX INFO BUTTONS OK.

  /* FOR EACH segment */
  /*DO:

  alert STS then alert 56 then 202 then due to holiday ( ie loop for elements )

  END. */
END.

3 个答案:

答案 0 :(得分:0)

这不是很优雅,我认为你的分隔符与你所暗示的一致,但在这里你去...

DEF VAR iCnt      AS INT  NO-UNDO.
DEF VAR ediString AS CHAR NO-UNDO.
DEF VAR segment   AS CHAR NO-UNDO.
DEF VAR iLoop     AS INT  NO-UNDO.
DEF VAR iLoop2     AS INT  NO-UNDO.
DEF VAR cSubString AS CHAR NO-UNDO.
DEF VAR cSubString2 AS CHAR NO-UNDO.
DEF VAR cValue      AS CHAR NO-UNDO.
DEF VAR iEntry      AS INT  NO-UNDO.
DEF TEMP-TABLE fred
  FIELD ParentID AS INT
  FIELD STRINGID AS INT
  FIELD ParseID  AS INT
  Field ParseValue    AS CHAR FORMAT "X(20)".
ediString = "STS++56+202:::DUE TO HOLIDAY1'STS++56+202:::DUE TO HOLIDAY2'STS++56+202:::DUE TO HOLIDAY3'". 

FUNCTION getEntry RETURNS INT ():
  iEntry = iEntry + 1.
  RETURN iEntry.
END.

DO  iCnt = 1 TO num-entries(ediString, "'") - 1  :

    ASSIGN segment = string(entry(iCnt, ediString, "'"))
           iEntry = 0.
  REPEAT iLoop = 1 TO NUM-ENTRIES(segment,"+"):


    cSubString =  ENTRY(iLoop,segment,"+").

    IF cSubString MATCHES "*:*" THEN
    DO:

      REPEAT iLoop2 = 1 TO  NUM-ENTRIES(cSubString,":"):

        cSubString2 =  ENTRY(iLoop2,cSubString,":").

        if cSubString2 = "" THEN NEXT.
        CREATE fred.
        ASSIGN  
          fred.ParentID = iCnt
          fred.StringID = iLoop
          fred.ParseID  = getEntry()
          fred.parseValue = cSubString2.
          cSubString2 = "".

      END.
    END. 
    ELSE
    DO:
     IF cSubString <> "" THEN
     DO:
       CREATE fred.
        ASSIGN  
          fred.ParentID = iCnt
          fred.StringID = iLoop
          fred.ParseID  = getEntry()
          fred.ParseValue = cSubString.
     END.
    END.


  END. 
END.

for each fred:
    display fred.
END.

答案 1 :(得分:0)

这个解决方案可能不是最好的,但假设你展示的模式,我认为这可以帮助你。

DEF TEMP-TABLE tt-data NO-UNDO
    FIELD sequence      AS INT
    FIELD string-1      AS CHAR FORMAT 'x(20)'
    FIELD string-2      AS CHAR FORMAT 'x(20)'
    FIELD string-3      AS CHAR FORMAT 'x(20)'
    FIELD string-4      AS CHAR FORMAT 'x(20)'
    INDEX ch-unique IS PRIMARY UNIQUE
        sequence.

DEF VAR i-seq           AS INT  NO-UNDO INIT 0.
DEF VAR c-aux           AS CHAR NO-UNDO EXTENT 4.
DEF VAR i-count         AS INT  NO-UNDO.
DEF VAR c-source        AS CHAR NO-UNDO.
DEF VAR c-data          AS CHAR NO-UNDO
    INIT "STS++56+202:::DUE TO HOLIDAY1'STS++56+202:::DUE TO HOLIDAY2'STS++56+202:::DUE TO HOLIDAY3'".

DO i-count = 1 TO NUM-ENTRIES(c-data,"'"):

    ASSIGN c-source = ENTRY(i-count,c-data,"'").

    IF TRIM(c-source)               = '' OR
       NUM-ENTRIES(c-source,'+')   <> 4  THEN
        NEXT.

    ASSIGN c-aux[1] = ENTRY(1,c-source,'+')
           c-aux[2] = ENTRY(3,c-source,'+')
           c-aux[3] = ENTRY(1,ENTRY(4,c-source,'+'),':')
           c-aux[4] = ENTRY(4,ENTRY(4,c-source,'+'),':').

    CREATE tt-data.
    ASSIGN i-seq                = i-seq + 1
           tt-data.sequence     = i-seq
           tt-data.string-1     = c-aux[1]
           tt-data.string-2     = c-aux[2]  
           tt-data.string-3     = c-aux[3]  
           tt-data.string-4     = c-aux[4].

END.

FOR EACH tt-data 
    BY sequence:

    DISP tt-data WITH WIDTH 333 NO-ERROR.

END.

答案 2 :(得分:0)

如果您只有两个分隔符,则此代码是一种干净的搜索方式。它可以扩展为三个或更多分隔符,但我可能会以不同的方式构造代码。 (我会遍历一个分隔符列表。如果你需要这样的代码,请告诉我。)

此代码的一个目的是最小化执行的字符串搜索的数量。不是在每次查找后搜索两个分隔符,而是只搜索一个分隔符。我相信这会使它在不失透明度的情况下保持高效 - 但我没有做基准测试,我可能错了。与往常一样,最佳解决方案将取决于数据的性质。

DEFINE VARIABLE v-edistring  AS CHARACTER   NO-UNDO.
DEFINE VARIABLE v-cnt AS INTEGER     NO-UNDO.
DEFINE VARIABLE segment AS CHARACTER   NO-UNDO.

DEFINE VARIABLE v-curpsn   AS INTEGER   NO-UNDO.
DEFINE VARIABLE v-idxplus  AS INTEGER   NO-UNDO.
DEFINE VARIABLE v-idxcolon AS INTEGER   NO-UNDO.
DEFINE VARIABLE v-element  AS CHARACTER NO-UNDO.

v-edistring = "STS++56+202:::DUE TO HOLIDAY1'STS++56+202:::DUE TO HOLIDAY2'STS++56+202:::DUE TO HOLIDAY3'".

DO  v-cnt = 1 TO num-entries(v-edistring, "'") - 1  :

   ASSIGN segment = string(entry(v-cnt, v-edistring, "'")).

   MESSAGE "SEGMENT: " segment
       VIEW-AS ALERT-BOX INFO BUTTONS OK.


  /*
  ** Cleverness here....
  ** Find the first positions of each delimiter in the segment
  **
  ** Then:
  ** Clip out an element of the segment up through the next nearest delim.
  ** Recalculate the next postion of that delimiter
  **  ... and loop
  */
  v-curpsn = 1.
  v-idxplus  = INDEX( segment, "+", v-curpsn).
  v-idxcolon = INDEX( segment, ":", v-curpsn).

  DO WHILE TRUE:

    IF v-idxplus = 0 THEN DO:
      IF v-idxcolon = 0 THEN LEAVE.  /* no more delimiters */

      /* Otherwise, next delim is a colon */
      v-element = SUBSTRING( segment, v-curPsn, v-idxcolon - v-curPsn).
      v-curpsn = v-idxcolon + 1.
      /* No need to recalculate v-idxplus */
      v-idxcolon  = INDEX( segment, ":", v-curpsn).

    END.
    ELSE DO:  /* v-idxplus > 0 */
      IF v-idxcolon = 0 OR v-idxcolon > v-idxplus THEN DO:

        /* Either no colons, or next delim is a plus */
        v-element = SUBSTRING( segment, v-curPsn, v-idxplus - v-curPsn).
        v-curpsn = v-idxplus + 1.
        /* No need to recalculate v-idxcolon */
        v-idxplus  = INDEX( segment, "+", v-curpsn).

      END.
      ELSE DO: /* both > 0, but idxplus is next delim */

        v-element = SUBSTRING( segment, v-curPsn, v-idxcolon - v-curPsn).
        v-curpsn = v-idxcolon + 1.
        /* No need to recalculate v-idxplus */
        v-idxcolon  = INDEX( segment, ":", v-curpsn).

      END.
    END.


    /* 
    ** Display result.  Skip empty elements.  If you want to ignore
    ** pure white space (e.g. " "), then you can change this to
    **    IF v-element <> ""
    */
    IF LENGTH( v-element) > 0 THEN DO:
      MESSAGE v-element
          VIEW-AS ALERT-BOX INFO BUTTONS OK.
    END.
  END.

  /*
  ** No more delimiters.  But there still might be one element left */
  IF v-curpsn < LENGTH( segment) THEN DO:
    v-element = SUBSTRING( segment, v-curPsn).
    MESSAGE v-element
      VIEW-AS ALERT-BOX INFO BUTTONS OK.
  END.

END