소스 검색

Find a proper way to parse dot separated values

jherve 1 년 전
부모
커밋
4332d84aa6
2개의 변경된 파일55개의 추가작업 그리고 18개의 파일을 삭제
  1. 38 12
      src/LinkedIn/UIElements/Parser.purs
  2. 17 6
      test/UIStringParser.purs

+ 38 - 12
src/LinkedIn/UIElements/Parser.purs

@@ -5,19 +5,23 @@ import Prelude
 import Control.Alt ((<|>))
 import Control.Alt ((<|>))
 import Data.Array as A
 import Data.Array as A
 import Data.Date (Month(..), Year)
 import Data.Date (Month(..), Year)
-import Data.Either (Either(..))
+import Data.Either (hush)
 import Data.Enum (toEnum)
 import Data.Enum (toEnum)
 import Data.Int (fromNumber)
 import Data.Int (fromNumber)
 import Data.List (List(..), (:))
 import Data.List (List(..), (:))
+import Data.List as L
+import Data.List.NonEmpty as NEL
+import Data.List.Types (NonEmptyList)
 import Data.Map (Map)
 import Data.Map (Map)
 import Data.Map as M
 import Data.Map as M
 import Data.Maybe (Maybe(..))
 import Data.Maybe (Maybe(..))
+import Data.String as S
 import Data.String.CodePoints (codePointFromChar)
 import Data.String.CodePoints (codePointFromChar)
 import Data.Tuple (Tuple(..))
 import Data.Tuple (Tuple(..))
 import LinkedIn.UIElements.Types (Duration(..), MonthYear(..), MonthYearOrToday(..), TimeSpan(..), UIString(..))
 import LinkedIn.UIElements.Types (Duration(..), MonthYear(..), MonthYearOrToday(..), TimeSpan(..), UIString(..))
-import Parsing (Parser, fail, runParser)
+import Parsing (Parser, ParserT, fail, liftMaybe, runParser)
 import Parsing.Combinators (choice, try)
 import Parsing.Combinators (choice, try)
-import Parsing.String (string, char, rest)
+import Parsing.String (char, rest, string)
 import Parsing.String.Basic (intDecimal, number, space, takeWhile)
 import Parsing.String.Basic (intDecimal, number, space, takeWhile)
 
 
 monthStrToMonth :: Map String Month
 monthStrToMonth :: Map String Month
@@ -131,17 +135,39 @@ stringWithoutMedianDotP = takeWhile (\c -> c /= codePointFromChar '·' && c /= c
 uiStringP :: Parser String UIString
 uiStringP :: Parser String UIString
 uiStringP = (try uiStringdotSeparatedP) <|> uiStringSingleP
 uiStringP = (try uiStringdotSeparatedP) <|> uiStringSingleP
 
 
+uiStringWithoutMedianDotP ∷ Parser String UIString
+uiStringWithoutMedianDotP = do
+  s <- rest
+  liftMaybe (\_ -> "nope") $ hush $ runParser s uiStringSingleP
+
 uiStringdotSeparatedP ∷ Parser String UIString
 uiStringdotSeparatedP ∷ Parser String UIString
 uiStringdotSeparatedP = do
 uiStringdotSeparatedP = do
-  subStr <- stringWithoutMedianDotP
-  _ <- medianDotP
-  _ <- space
-  sub2Str <- rest
-  case runParser subStr uiStringSingleP of
-    Right sub -> case runParser sub2Str uiStringSingleP of
-      Right sub2 -> pure $ UIStringDotSeparated sub sub2
-      Left _ -> fail "not a sub"
-    Left _ -> fail "not a sub"
+  Tuple s1 s2 <- medianDotSeparated
+
+  let
+    intoUiElement :: String -> Parser String UIString
+    intoUiElement s = liftMaybe (\_ -> "could not convert to ui element") $ hush $ runParser s uiStringSingleP
+
+  s1' <- intoUiElement s1
+  s2' <- intoUiElement s2
+
+  pure $ UIStringDotSeparated s1' s2'
+
+sepBy2 :: forall m s a sep. ParserT s m a -> ParserT s m sep -> ParserT s m (NonEmptyList a)
+sepBy2 p sep = do
+  a0 <- p
+  a1 <- sep *> p
+  as <- L.manyRec $ sep *> p
+  pure $ NEL.cons a0 $ NEL.cons' a1 as
+
+commaSeparated ∷ Parser String (NonEmptyList String)
+commaSeparated = stringWithoutCommaP `sepBy2` commaP
+
+medianDotSeparated ∷ Parser String (Tuple String String)
+medianDotSeparated = do
+  a0 <- stringWithoutMedianDotP
+  a1 <- medianDotP *> rest
+  pure $ Tuple (S.trim a0) (S.trim a1)
 
 
 uiStringSingleP ∷ Parser String UIString
 uiStringSingleP ∷ Parser String UIString
 uiStringSingleP = (try uiStringDurationP) <|> (try uiStringTimeSpanP) <|> uiStringPlainP
 uiStringSingleP = (try uiStringDurationP) <|> (try uiStringTimeSpanP) <|> uiStringPlainP

+ 17 - 6
test/UIStringParser.purs

@@ -3,13 +3,14 @@ module Test.UIStringParser
   )
   )
   where
   where
 
 
+import Prelude
+
 import Data.Date (Month(..))
 import Data.Date (Month(..))
 import Data.Either (Either(..))
 import Data.Either (Either(..))
 import Effect (Effect)
 import Effect (Effect)
 import LinkedIn.UIElements.Parser (durationP, monthYearP, timeSpanP, uiStringDurationP, uiStringdotSeparatedP)
 import LinkedIn.UIElements.Parser (durationP, monthYearP, timeSpanP, uiStringDurationP, uiStringdotSeparatedP)
 import LinkedIn.UIElements.Types (Duration(..), TimeSpan(..), UIString(..))
 import LinkedIn.UIElements.Types (Duration(..), TimeSpan(..), UIString(..))
-import Parsing (runParser)
-import Prelude (Unit, discard)
+import Parsing (ParseError(..), Position(..), runParser)
 import Test.Assert (assertEqual)
 import Test.Assert (assertEqual)
 import Test.Utils (toMonthYear')
 import Test.Utils (toMonthYear')
 
 
@@ -76,13 +77,23 @@ testUIParserDuration = do
 testUIParserDotSeparated ∷ Effect Unit
 testUIParserDotSeparated ∷ Effect Unit
 testUIParserDotSeparated = do
 testUIParserDotSeparated = do
   assertEqual {
   assertEqual {
-    actual: run "2 ans 3 mois · some text",
-    expected: Right(UIStringDotSeparated (UIStringDuration (YearsMonth 2 3)) (UIStringPlain "some text"))
+    actual: run "some text 1 · some text 2",
+    expected: Right(UIStringDotSeparated (UIStringPlain "some text 1") (UIStringPlain "some text 2"))
+  }
+
+  assertEqual {
+    actual: run "· some text after a dot",
+    expected: Right(UIStringDotSeparated (UIStringPlain "") (UIStringPlain "some text after a dot"))
+  }
+
+  assertEqual {
+    actual: run "some text before a dot ·",
+    expected: Right(UIStringDotSeparated (UIStringPlain "some text before a dot") (UIStringPlain ""))
   }
   }
 
 
   assertEqual {
   assertEqual {
-    actual: run "· Boulogne-Billancourt, Île-de-France, France",
-    expected: Right(UIStringDotSeparated (UIStringPlain "") (UIStringPlain "Boulogne-Billancourt, Île-de-France, France"))
+    actual: run "string with no dot",
+    expected: (Left (ParseError "Expected '•'" (Position { column: 19, index: 18, line: 1 })))
   }
   }
 
 
   where run s = runParser s uiStringdotSeparatedP
   where run s = runParser s uiStringdotSeparatedP