diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,12 @@
 # Changelog for hascard
-##
+## 0.5.0.3
+New:
+- Improved `hascard import` functionality: delimiters can be specified via CLI options (fixes issue #17).
+
+Fixed bug:
+- Removed redundant newline after header
+
+## 0.5.0.2
 New:
 - Setting for changing case sensitivity of open questions. Default behaviour is case sensitive, which was also the functionality before this setting was added.
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
 # hascard
-[![Build Status](https://travis-ci.org/Yvee1/hascard.svg?branch=master)](https://travis-ci.org/Yvee1/hascard) [![GitHub tag](https://img.shields.io/github/tag/Yvee1/hascard.svg)](https://github.com/Yvee1/hascard/releases) [![AUR](https://img.shields.io/aur/version/hascard)](https://aur.archlinux.org/packages/hascard/) [![Hackage](https://img.shields.io/hackage/v/hascard.svg)](https://hackage.haskell.org/package/hascard)
+[![Build Status]()](https://github.com/Yvee1/hascard/actions/workflows/build.yml/badge.svg) [![GitHub tag](https://img.shields.io/github/tag/Yvee1/hascard.svg)](https://github.com/Yvee1/hascard/releases) [![AUR](https://img.shields.io/aur/version/hascard)](https://aur.archlinux.org/packages/hascard/) [![Hackage](https://img.shields.io/hackage/v/hascard.svg)](https://hackage.haskell.org/package/hascard)
 
 
 
@@ -64,7 +64,7 @@
 As an example, say you have a file `deck.txt` with lots of cards in it and you want to review 5 random ones, you can use `hascard run deck -s -a 5`. Here `-s` shuffles the deck and `-a 5` specifies we only want to look at 5 of them. For more info, see `hascard run --help`.
 
 #### Importing decks
-If you have decks in a different format, you might want to convert them into files compatible with hascard. Currently tab-seperated files can be converted to definition or open question cards. For example [Quizlet](https://quizlet.com/) decks can be exported to this format. As an example, the following file
+If you have decks in a different format, you might want to convert them into files compatible with hascard. Currently, delimited text files can be converted to definition or open question cards. For example [Quizlet](https://quizlet.com/) decks can be exported to this format. As an example, the following file
 ```
 aussi	ook
 en outre, de plus	bovendien
diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -5,14 +5,17 @@
 import Control.Exception (displayException, try)
 import Control.Monad (void, when)
 import Data.Version (showVersion)
+import Data.Void
 import Lens.Micro.Platform
 import Paths_hascard (version)
 import Parser
-import Options.Applicative
+import Options.Applicative hiding (many)
 import System.Directory (makeAbsolute)
 import System.FilePath (takeExtension, takeBaseName, takeDirectory)
 import System.Process (runCommand)
 import System.Random.MWC (createSystemRandom)
+import Text.Megaparsec (parse, many, errorBundlePretty, ParseErrorBundle)
+import Text.Megaparsec.Char.Lexer (charLiteral)
 import qualified Data.Map.Strict as Map (empty)
 import qualified System.Directory as D
 import qualified Stack
@@ -34,12 +37,6 @@
   , _optBlankMode    :: Bool
   }
 
-data ImportOpts = ImportOpts
-  { _optInput         :: String 
-  , _optOutput        :: String
-  , _optImportType    :: ImportType
-  , _optImportReverse :: Bool }
-
 makeLenses ''Opts
 makeLenses ''RunOpts
 makeLenses ''ImportOpts
@@ -63,7 +60,10 @@
 opts = Opts
   <$> optional (hsubparser
     (  command "run" (info (Run <$> runOpts) ( progDesc "Run hascard with CLI options"))
-    <> command "import" (info (Import <$> importOpts) (progDesc "Convert a TAB delimited file to syntax compatible with hascard. So, terms and definitions should be seperated by tabs, and rows by new lines. When converting to 'open' cards, multiple correct answers can be seperated by semicolons (;), backslashes (/) or commas (,)."))))
+    <> command "import" (info (Import <$> importOpts) (progDesc "Convert a delimited text file (e.g. exported from Quizlet) to a file compatible with hascard.\
+    \ The delimiters can be specified via CLI options. By default, terms and definitions are assumed to be separated by tabs, and different cards by new lines.\
+    \ Either 'Definition' cards are generated (traditional flashcards), or 'Open question' cards (where the answer needs to be typed).\
+    \ For 'Open question' cards, a delimiter can be specified which separates multiple correct answers."))))
   <*> switch (long "version" <> short 'v' <> help "Show version number")
 
 runOpts :: Parser RunOpts
@@ -76,14 +76,18 @@
 
 importOpts :: Parser ImportOpts
 importOpts = ImportOpts
-  <$> argument str (metavar "INPUT" <> help "A TSV file")
+  <$> argument str (metavar "INPUT" <> help "A delimited text file")
   <*> argument str (metavar "DESINATION" <> help "The filename/path to which the output should be saved")
-  <*> option auto (long "type" <> short 't' <> metavar "'open' or 'def'" <> help "The type of card to which the input is transformed, default: open" <> value Open)
+  <*> option auto (long "type" <> short 't' <> metavar "'open' or 'def'" <> help "The type of card to which the input is transformed; default: open." <> value Open)
   <*> switch (long "reverse" <> short 'r' <> help "Reverse direction of question and answer, i.e. right part becomes the question.")
+  <*> strOption (long "row-delimiter" <> metavar "delimiter" <> help "The delimiter used to separate different cards; default: \\n." <> value "\n")
+  <*> strOption (long "term-def-delimiter" <> metavar "delimiter" <> help "The delimiter used to separate terms and definitions; default: \\t." <> value "\t")
+  <*> optional (strOption (long "def-delimiter" <> metavar "delimiter" <> help "The delimiter used to separate different definitions for the same term; no delimiter is used by default."))
 
 optsWithHelp :: ParserInfo Opts
 optsWithHelp = info (opts <**> helper) $
-              fullDesc <> progDesc "Run the normal application with `hascard`. To run directly on a file, and with CLI options, see `hascard run --help`. For converting TAB seperated files, see `hascard import --help`."
+              fullDesc <> progDesc "Run the normal application with `hascard`. To run directly on a file, and with CLI options, see `hascard run --help`.\
+              \ For converting delimited text files, see `hascard import --help`."
               <> header "Hascard - a TUI for reviewing notes"
 
 nothingIf :: (a -> Bool) -> a -> Maybe a
@@ -138,15 +142,20 @@
 start (Just (fp, cards)) gs = runBrickFlashcards =<< (gs `goToState`) <$> cardsWithOptionsState gs fp cards
 
 doImport :: ImportOpts -> IO ()
-doImport opts = do
+doImport opts' = do
+  let opts = opts' & optRowDelimiter %~ parseStringLiteral
   valOrExc <- try $ readFile (opts ^. optInput) :: IO (Either IOError String)
   case valOrExc of
     Left exc -> putStrLn (displayException exc)
     Right val -> do
-      let mCards = parseImportInput (opts ^. optImportType) (opts ^. optImportReverse) val
+      let mCards = parseImportInput opts val
       case mCards of
-        Just cards -> do
+        Right cards -> do
           writeFile (opts ^. optOutput) . cardsToString $ cards
           putStrLn "Successfully converted the file."
-        Nothing -> putStrLn "Failed the conversion."
+        Left msg -> putStrLn msg
          
+parseStringLiteral :: String -> String
+parseStringLiteral s = case parse (many charLiteral) "" s of
+  Left errorBundle -> error (errorBundlePretty (errorBundle :: ParseErrorBundle String Void))
+  Right result -> result
diff --git a/hascard.cabal b/hascard.cabal
--- a/hascard.cabal
+++ b/hascard.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 37031709ac5e49c9833f7bc7e63a8db75834eda98879221fc1968c2e15fb231d
+-- hash: 6236002c595a937b392daea7195014259e4161b14760978c156dbcf4a7dcc106
 
 name:           hascard
-version:        0.5.0.2
+version:        0.5.0.3
 synopsis:       A TUI for reviewing notes using 'flashcards' written with markdown-like syntax.
 description:    Hascard is a text-based user interface for reviewing notes using flashcards. Cards are written in markdown-like syntax. Please see the README file on GitHub at <https://github.com/Yvee1/hascard#readme> for more information.
 category:       Application
diff --git a/src/Import.hs b/src/Import.hs
--- a/src/Import.hs
+++ b/src/Import.hs
@@ -1,12 +1,30 @@
+{-# LANGUAGE TemplateHaskell #-}
 module Import where
+import Control.Monad (void)
 import Data.Char (toLower, isSpace)
 import Data.List
-import Data.List.Split
+-- import Data.List.Split
 import qualified Data.List.NonEmpty as NE
+import Data.Void
+import Lens.Micro.Platform
+import Text.Megaparsec
+import Text.Megaparsec.Char
+import Text.Megaparsec.Debug
 import Types
 
 data ImportType = Def | Open
 
+data ImportOpts = ImportOpts
+  { _optInput            :: String 
+  , _optOutput           :: String
+  , _optImportType       :: ImportType
+  , _optImportReverse    :: Bool
+  , _optRowDelimiter     :: String
+  , _optTermDefDelimiter :: String
+  , _optDefDelimiter     :: Maybe String }
+
+makeLenses ''ImportOpts
+
 instance Read ImportType where
   readsPrec _ input =
     case map toLower input of
@@ -15,14 +33,64 @@
          | "definition" `isPrefixOf` xs -> [(Def, drop 10 xs)]
          | otherwise -> []
 
-parseImportInput :: ImportType -> Bool -> String -> Maybe [Card]
-parseImportInput iType reverse input = 
-  let listToTuple [q, a] = Just $ if not reverse then (q, a) else (a, q)
-      listToTuple _ = Nothing
-      xs = mapM (listToTuple . splitOn "\t") (lines input)
-      makeOpen (header, body) = OpenQuestion header Nothing
-        (P "" (NE.fromList (map (dropWhile isSpace) (splitOneOf ",/;" body))) (Normal ""))
+type Parser = Parsec Void String
 
-  in case iType of
-    Def  -> map (\(s1, s2) -> Definition s1 Nothing s2) <$> xs
-    Open -> map makeOpen <$> xs 
+rowDelimiter :: String
+rowDelimiter = "\n\n"
+
+termDefDelimiter :: String
+termDefDelimiter = "\t"
+
+defDelimiter :: String
+defDelimiter = ","
+
+parseImportInput :: ImportOpts -> String -> Either String [Card]
+parseImportInput opts s = case parse (pImportInput opts) "failed import parsing" s of
+  Left parseErrorBundle -> Left $ errorBundlePretty (parseErrorBundle :: ParseErrorBundle String Void)
+  Right cards -> Right cards
+
+pImportInput :: ImportOpts -> Parser [Card]
+pImportInput opts = pRow opts `sepEndBy1` (void (try (pRowDelimiter *> eol)) <|> void pRowDelimiter <|> void (many eol) <|> eof)
+  where pRowDelimiter = string (opts ^. optRowDelimiter)
+
+pRow :: ImportOpts -> Parser Card
+pRow opts =
+  let
+    pTermDefDelimiter = string (opts ^. optTermDefDelimiter)
+    pDefDelimiter = string <$> (opts ^. optDefDelimiter)
+    pTerm = manyTill anySingle . lookAhead . try $ pSpecial opts
+    pDefs = maybe (fmap (:[]) (pDef opts)) (pDef opts `sepBy`) pDefDelimiter
+    defBeforeTerm = opts ^. optImportReverse
+  in
+    case (defBeforeTerm, opts ^. optImportType) of
+      (False, Open) -> do
+        term <- pTerm
+        pTermDefDelimiter
+        defs <- pDefs
+        return $ OpenQuestion (filter (/= '\n') term) Nothing (P "" (NE.fromList (map (dropWhile isSpace) defs)) (Normal ""))
+      (True, Open) -> do
+        defs <- pDefs
+        pTermDefDelimiter
+        term <- pTerm
+        return $ OpenQuestion (filter (/= '\n') term) Nothing (P "" (NE.fromList (map (dropWhile isSpace) defs)) (Normal ""))
+      (False, Def) -> do
+        term <- pTerm
+        pTermDefDelimiter
+        def <- pDef opts
+        return $ Definition (filter (/= '\n') term) Nothing def
+      (True, Def) -> do
+        def <- pDef opts
+        pTermDefDelimiter
+        term <- pTerm
+        return $ Definition (filter (/= '\n') term) Nothing def
+
+pDef :: ImportOpts -> Parser String
+pDef opts = maybe
+  (manyTill anySingle . lookAhead . try $ pSpecial opts)
+  (\pDefDelimiter -> manyTill anySingle . lookAhead . try $ void pDefDelimiter <|> pSpecial opts)
+  (string <$> (opts ^. optDefDelimiter))
+
+pSpecial :: ImportOpts -> Parser ()
+pSpecial opts = void pTermDefDelimiter <|> void pRowDelimiter <|> (eol *> eof) <> eof
+  where pTermDefDelimiter = string (opts ^. optTermDefDelimiter)
+        pRowDelimiter = string (opts ^. optRowDelimiter)
diff --git a/src/Types.hs b/src/Types.hs
--- a/src/Types.hs
+++ b/src/Types.hs
@@ -36,14 +36,14 @@
 instance Show Card where
   show card = let showHeader h = "# " <> h <> "\n"
     in case card of
-      Definition h img descr -> showHeader h <> maybe "" show img <> "\n" <> descr
-      OpenQuestion h img p -> showHeader h <> maybe "" show img <> "\n" <> show p
+      Definition h img descr -> showHeader h <> maybe "" ((<>"\n") . show) img <> descr
+      OpenQuestion h img p -> showHeader h <> maybe "" ((<>"\n") . show) img <> show p
       MultipleChoice h img c inc -> 
-        showHeader h <> maybe "" show img <> "\n" <> showMultipleChoice c inc
+        showHeader h <> maybe "" ((<>"\n") . show) img <> showMultipleChoice c inc
       MultipleAnswer h img opts ->
-        showHeader h <> maybe "" show img <> "\n" <> unlines' (NE.toList (NE.map show opts))
+        showHeader h <> maybe "" ((<>"\n") . show) img <> unlines' (NE.toList (NE.map show opts))
       Reorder h img elts -> 
-        showHeader h <>maybe "" show img <> "\n" <> unlines' (NE.toList (NE.map showReorder elts))
+        showHeader h <>maybe "" ((<>"\n") . show) img <> unlines' (NE.toList (NE.map showReorder elts))
 
 --              alt   file
 data External = Image String String
diff --git a/src/UI.hs b/src/UI.hs
--- a/src/UI.hs
+++ b/src/UI.hs
@@ -8,6 +8,7 @@
 , Card
 , External
 , ImportType(..)
+, ImportOpts(..)
 , Parameters(..)
 
 , goToState
