Attoparsec を使用して、正確に 1 つの 'x'、1 つの 'y'、および 1 つの 'z' と、任意の数の 'a'、'b'、または 'c' を含む文字列を、順序に制約なしで一致させようとしています。各文字の。
たとえば、「abbb z ac y aaa x cba」と「abbb z ac x aaa y cba」は一致するはずですが、次のものは一致しません。
- "abbb z ac y aaacba" (理由: no 'x')
- "abbb z ac y aaa x cb x a" (理由: 重複 'x')
これまでに私ができる最高のことはこれです:
import qualified Data.Attoparsec.ByteString.Char8 as A8
import qualified Data.ByteString.Char8 as B8 (pack)
p ch = do
abcs <- A8.many' (A8.choice [A8.char 'a', A8.char 'b', A8.char 'c'])
x <- A8.char ch
return $ concat [[x],abcs]
parse = do
xyz1 <- A8.choice [p 'x', p 'y', p 'z']
xyz2 <- A8.choice [p 'x', p 'y', p 'z']
xyz3 <- A8.choice [p 'x', p 'y', p 'z']
final <- A8.manyTill (A8.choice [A8.char 'a', A8.char 'b', A8.char 'c']) $ A8.char '\n'
return (xyz1, xyz2, xyz3, final)
(任意に、'\n' で解析を停止することにしましたが、それは単純な例を選ぶためです)。
次にghciで試します:
Prelude> A8.parseTest parse $ B8.pack "abbbzacyaaaxcba\n"
Done "" ("zabbb","yac","xaaa", "cba")
Prelude> A8.parseTest parse $ B8.pack "abbbzacyaaacba\n"
Fail "aaacba\n" [] "Failed reading: empty"
Prelude> A8.parseTest parse $ B8.pack "abbbzacyaaaxcbxa\n"
Fail "xa\n" [] "Failed reading: empty"
しかし、それは非常に不格好に見え、一意の文字のリストに簡単に拡張することはできません (たとえば、与えられた givenchars :: [Char] リストが重複していない場合、すべての givenchars と任意の 'a で構成される任意の文字列に一致させたい','b','c は任意の順序で間にあります)。
これを行うための、より優れた、よりエレガントでスケーラブルな方法はありますか?
PS: 正規表現のソリューションは、実際の問題には当てはまらないため、探していません。パーサーを使用する必要があります。