You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Parsec提取字符串中符合特定模式的子串?

解决Haskell Parsec提取特定F开头子串的问题

嘿,作为Haskell和Parsec的新手,碰到这种提取特定模式子串的问题太正常了!我来帮你一步步搞定这个需求~

首先咱们明确下你要匹配的模式细节,避免歧义:

  • 必须以大写F开头(如果需要支持小写可以轻松调整)
  • F后面可以跟0个或多个空格
  • 空格之后必须有至少一个数字(这一步是关键,直接排除了单独的F)
  • 数字之后可以跟任意非空白字符(比如字母、括号、连字符等),直到遇到下一个空白为止

接下来直接上代码,我会逐行解释,方便你理解:

1. 导入必要的Parsec模块

首先得导入Parsec的核心模块和字符串解析器:

import Text.Parsec
import Text.Parsec.String (Parser)  -- 我们用String类型作为输入源

2. 定义核心匹配模式的Parser

先写一个Parser来匹配单个符合要求的子串:

-- 匹配符合要求的F开头子串
fPattern :: Parser String
fPattern = do
  -- 匹配开头的大写F
  start <- char 'F'
  -- 匹配0个或多个空白字符(支持空格、制表符等)
  spacesBetween <- many space
  -- 匹配至少一个数字:这一步确保不会匹配单独的F
  digits <- many1 digit
  -- 匹配数字后面的所有非空白字符(直到遇到空格/换行)
  suffix <- many (noneOf " \t\n\r")
  -- 把所有部分拼接起来返回
  return $ start : spacesBetween ++ digits ++ suffix

3. 定义提取所有匹配项的Parser

接下来需要一个Parser遍历整个字符串,收集所有符合要求的子串,同时跳过不匹配的内容(包括单独的F):

-- 提取字符串中所有符合fPattern的子串
extractAllFPatterns :: Parser [String]
extractAllFPatterns = do
  -- 收集所有匹配结果
  matches <- many $ do
    -- 跳过所有不是F的字符,直到遇到下一个F
    skipMany (noneOf "F")
    -- 尝试匹配完整的fPattern:
    -- 如果匹配成功,返回该子串;如果失败(比如F后面没有数字),就跳过这个F,返回空字符串
    try fPattern <|> (char 'F' >> return "")
  -- 过滤掉空字符串(那些被跳过的单独F)
  return $ filter (not . null) matches

4. 测试代码

用你的测试字符串验证效果:

testString :: String
testString = "I want to choose F12 or F 12 from F1(a), F2a, F5-A, F34-5 and so on"

main :: IO ()
main = case parse extractAllFPatterns "" testString of
  Left err -> putStrLn $ "解析错误:" ++ show err
  Right results -> print results

运行这段代码,你会得到预期的结果:

["F12","F 12","F1(a)","F2a","F5-A","F34-5"]

一些边缘情况说明

  • 单独的F:比如字符串中的"Hello F world",这个F不会被提取,因为后面没有数字
  • 多空格分隔:比如"F 789XYZ"会被完整提取为"F 789XYZ"
  • 特殊字符后缀:比如"F0!@#$"会被提取为"F0!@#$"

如果需要支持小写f,只需要把char 'F'改成oneOf "Ff"即可~

内容的提问来源于stack exchange,提问作者Z-Y.L

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:28:02