2016-03-28 107 views
1

我有一個字符串如何提取由分隔符進行分隔的字符串opensge 4gl?

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

撇號(')表示線的終止,每一行是一個段。我已經提取每個段並將其分配給變量段。

現在對於每個段,我需要循環查找元素(STS,56,202,由於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. 

回答

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. 
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. 
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