haskell ReadP(< ++)函数问题

时间:2017-09-20 14:31:00

标签: parsing haskell

目前我正在尝试通过为某种类型的日志文件编写解析器来学习Haskell。

如果我执行以下singleBlock解析器:

singleBlock :: ReadP (String, String)
singleBlock = do
   st <- look

   if "LOAD INCREMENT" `isInfixOf` st then do
       fmap (head . splitOn "LOAD INCREMENT") look >>= string
       increment <- (munch PP.nonDigit >> munch PP.floatDot) 

       fmap (head. splitOn "STEP") look >>= string
       munch PP.nonDigit
       step <- munch PP.digit

    return (increment, step)
   else pfail

它产生以下输出:

[("3.000E-01","1"),("3.000E-01","2"),("3.000E-01","3"),("1.000E-01","4"),("1","5")]

问题是,在第5步,文件发生了变化,因此Float不再被解析。

如果我将增量​​线更改为:

increment <- (munch PP.nonDigitOnLine >> munch PP.floatDot >> munch PP.nonDigitOnLine >> munch PP.floatDot)

[("","1"),("","2"),("","3"),("","4"),("2.500E-01","5")]

正确解析fift步骤。前4个步骤产生一个空字符串,因此我认为我可以将increment line更改为:

increment <- (munch PP.nonDigitOnLine >> munch PP.floatDot >> munch PP.nonDigitOnLine >> munch PP.floatDot) <++ (munch PP.nonDigit >> munch PP.floatDot)

使用左侧偏向的<++选项。然而,它并没有改变我的输出:

[("","1"),("","2"),("","3"),("","4"),("2.500E-01","5")]

编辑:

日志文件是这样的(关注LOAD INCREMENT行):

 STEP      4 INITIATED:
   LOAD INCREMENT:  START STEPS *   1.000E-01
      SPARSE: DIM=272114 NNZ(MAT)=19119044
      SOLVE: REDUCTION RES= 0.14E-12 (INIT. RES= 0.96E+06) NI=    1
      ETA-ENERGY DIAGRAM    0    0.000E+00    3.182E+02
      ETA-ENERGY DIAGRAM    1    1.000E+00    2.344E+00

  STEP      4 : DISPLACEMENT NORM =  3.851E-03         TOLERANCE =  1.000E-02
  STEP      4 : FORCE NORM        =  6.558E+05         TOLERANCE =  1.000E-02

  RELATIVE OUT OF BALANCE FORCE   =  2.708E-01         CHECK = FALSE

      SPARSE: DIM=272114 NNZ(MAT)=19119044
      SOLVE: REDUCTION RES= 0.44E-14 (INIT. RES= 0.18E+06) NI=    1
      ETA-ENERGY DIAGRAM    0    0.000E+00    2.239E+00
      ETA-ENERGY DIAGRAM    1    1.000E+00    1.464E+00

 ...
 ...

  RELATIVE DISPLACEMENT VARIATION =  6.156E-03         CHECK = TRUE
  RELATIVE OUT OF BALANCE FORCE   =  1.722E-01         CHECK = FALSE

  STEP      4 TERMINATED, CONVERGENCE AFTER   2 ITERATIONS
  EXECUTION STOPPED ON TOTAL LOAD CRITERION
  CONTINUED ANALYSIS POSSIBLE.
   TOTAL LOAD FACTOR:  LOADING(12) *   1.000E+00

   PLASTICITY LOGGING SUMMARY
   GROUP NAME          PLAST, PRV. PL, CRITIC, PLAST NEW, PRV.PL NEW, CRITIC NEW
   TOTAL MODEL             0        0       0          0           0           0
   CRACKING LOGGING SUMMARY
   GROUP NAME               CRACK,     OPEN,   CLOSED,   ACTIVE,   INACTI,   ARISES, RE-OPENS,   CLOSES
   TOTAL MODEL                698       698         0       694         4       209         0         0
     CUMULATIVE REACTION:         FORCE X        FORCE Y          FORCE Z
                                0.89594D-09     0.11246D+02    -0.67820D-08


  STEP      5 INITIATED:
   LOAD INCREMENT:  LOADING( 1) *   2.500E-01
      SPARSE: DIM=272114 NNZ(MAT)=19119044
      SOLVE: REDUCTION RES= 0.53E-10 (INIT. RES= 0.11E+06) NI=    1

  STEP      5 : ENERGY NORM       =  7.379E+02         TOLERANCE =  1.000E-04


      SPARSE: DIM=272114 NNZ(MAT)=19119044
      SOLVE: REDUCTION RES= 0.56E-14 (INIT. RES= 0.11E+06) NI=    1

  ...
  ...

  STEP      5 TERMINATED, CONVERGENCE AFTER  13 ITERATIONS
   TOTAL LOAD FACTOR:  LOADING( 1) *   2.500E-01

1 个答案:

答案 0 :(得分:1)

仅仅20分钟后,事实证明我在问问题时很快乐。

问题是munch函数总是成功,因此我需要提供一个辅助函数,当解析后的字符串为null时它会失败。

isFloatDot = do
    s <- munch floatDot
    if null s then pfail
        else return s

以下代码段会生成正确的输出:

singleBlock :: ReadP (String, String)
singleBlock = do
    st <- look

    if "LOAD INCREMENT" `isInfixOf` st then do
        fmap (head . splitOn "LOAD INCREMENT") look >>= string

        increment <- (munch PP.nonDigitOnLine >> munch PP.floatDot >> munch PP.nonDigitOnLine >> PP.isFloatDot) <++ (munch PP.nonDigit >> munch PP.floatDot)
        fmap (head. splitOn "STEP") look >>= string
        munch PP.nonDigit
        step <- munch PP.digit

        return (increment, step)
    else pfail