jjzjj

regex - 在 golang 正则表达式中获取子组的命名列表

coder 2024-07-05 原文

我正在寻找一个返回 map[string]interface{} 的函数,其中 interface{} 可以是一个 slice ,一个 map[string ]interface{} 或一个值。

我的用例是像下面这样解析 WKT 几何图形并检索点值; donut 多边形示例:

多边形 ((0 0, 0 10, 10 10, 10 0, 0 0),(3 3, 3 7, 7 7, 7 3, 3 3))

正则表达式(出于可读性目的,我自愿设置\d 只匹配整数):

(POLYGON \(
    (?P<polygons>\(
        (?P<points>(?P<point>(\d \d), ){3,})
        (?P<last_point>\d \d )\),)*
    (?P<last_polygon>\(
        (?P<points>(?P<point>(\d \d), ){3,})
        (?P<last_point>\d \d)\))\)
)

我有一个函数(从 SO 复制)可以检索一些信息,但它对嵌套组和组列表不是很好:

func getRegexMatchParams(reg *regexp.Regexp, url string) (paramsMap map[string]string) {
    match := reg.FindStringSubmatch(url)
    paramsMap = make(map[string]string)
    for i, name := range reg.SubexpNames() {
        if i > 0 && i <= len(match) {
            paramsMap[name] = match[i]
        }
    }
    return match
}

点数组似乎只得到1分。 example on playground

[编辑] 我想要的结果是这样的:

map[string]interface{}{
    "polygons": map[string]interface{} {
        "points": []interface{}{
            {map[string]string{"point": "0 0"}},     
            {map[string]string{"point": "0 10"}},        
            {map[string]string{"point": "10 10"}},        
            {map[string]string{"point": "10 0"}},
        },
        "last_point": "0 0",
    },
    "last_polygon": map[string]interface{} {
        "points": []interface{}{
            {map[string]string{"point": "3 3"}},     
            {map[string]string{"point": "3 7"}},        
            {map[string]string{"point": "7 7"}},        
            {map[string]string{"point": "7 3"}},
        },
        "last_point": "3 3",
    }
}

因此我可以将它进一步用于不同的目的,例如查询数据库并验证每个多边形的 last_point = points[0]。

最佳答案

尝试在正则表达式中添加一些空格。

另请注意,此引擎不会保留所有
在量化的外部分组中,如 (a|b|c)+该组将仅包含它找到的最后一个 a 或 b 或 c。

而且,你的正则表达式可以简化为这个

(POLYGON\s*\((?P<polygons>\(\s*(?P<points>(?P<point>\s*(\d+\s+\d+)\s*,){3,})\s*(?P<last_point>\d+\s+\d+)\s*\)(?:\s*,\s*|\s*\)))+)

https://play.golang.org/p/rLaaEa_7GX


原文:

(POLYGON\s*\((?P<polygons>\(\s*(?P<points>(?P<point>\s*(\d+\s+\d+)\s*,){3,})\s*(?P<last_point>\d+\s+\d+)\s*\),)*(?P<last_polygon>\(\s*(?P<points>(?P<point>\s*(\d+\s+\d+)\s*,){3,})\s*(?P<last_point>\d+\s+\d+)\s*\))\s*\))

https://play.golang.org/p/rZgJYPDMzl

有关组包含的内容,请参见下文。

 (                             # (1 start)
      POLYGON \s* \(
      (?P<polygons>                 # (2 start)
           \( \s* 
           (?P<points>                   # (3 start)
                (?P<point>                    # (4 start)
                     \s* 
                     ( \d+ \s+ \d+ )               # (5)
                     \s* 
                     , 
                ){3,}                         # (4 end)
           )                             # (3 end)
           \s*            
           (?P<last_point> \d+ \s+ \d+ )  # (6)
           \s* \),
      )*                            # (2 end)
      (?P<last_polygon>             # (7 start)
           \( \s* 
           (?P<points>                   # (8 start)
                (?P<point>                    # (9 start)
                     \s* 
                     ( \d+ \s+ \d+ )               # (10)
                     \s* 
                     , 
                ){3,}                         # (9 end)
           )                             # (8 end)
           \s* 
           (?P<last_point> \d+ \s+ \d+ )  # (11)
           \s* \)
      )                             # (7 end)
      \s* \)
 )                             # (1 end)

输入

POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0),(3 3, 3 7, 7 7, 7 3, 3 3))

输出

 **  Grp 0                -  ( pos 0 , len 65 ) 
POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0),(3 3, 3 7, 7 7, 7 3, 3 3))  
 **  Grp 1                -  ( pos 0 , len 65 ) 
POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0),(3 3, 3 7, 7 7, 7 3, 3 3))  
 **  Grp 2 [polygons]     -  ( pos 9 , len 30 ) 
(0 0, 0 10, 10 10, 10 0, 0 0),  
 **  Grp 3 [points]       -  ( pos 10 , len 23 ) 
0 0, 0 10, 10 10, 10 0,  
 **  Grp 4 [point]        -  ( pos 27 , len 6 ) 
 10 0,  
 **  Grp 5                -  ( pos 28 , len 4 ) 
10 0  
 **  Grp 6 [last_point]   -  ( pos 34 , len 3 ) 
0 0  
 **  Grp 7 [last_polygon] -  ( pos 39 , len 25 ) 
(3 3, 3 7, 7 7, 7 3, 3 3)  
 **  Grp 8 [points]       -  ( pos 40 , len 19 ) 
3 3, 3 7, 7 7, 7 3,  
 **  Grp 9 [point]        -  ( pos 54 , len 5 ) 
 7 3,  
 **  Grp 10                -  ( pos 55 , len 3 ) 
7 3  
 **  Grp 11 [last_point]   -  ( pos 60 , len 3 ) 
3 3  

可能的解决方案

这并非不可能。它只需要几个额外的步骤。
(顺便说一句,WKT 没有可以为您解析的库吗?)

现在,我不知道你的语言能力,所以这只是一个通用的方法。

<强>1。验证您正在解析的表单。
这将验证并返回所有多边形集 作为 All_Polygons 中的单个字符串团体。

目标 POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0),(3 3, 3 7, 7 7, 7 3, 3 3))

POLYGON\s*\((?P<All_Polygons>(?:\(\s*\d+\s+\d+(?:\s*,\s*\d+\s+\d+){2,}\s*\))(?:\s*,\(\s*\d+\s+\d+(?:\s*,\s*\d+\s+\d+){2,}\s*\))*)\s*\)

 **  Grp 1 [All_Polygons] -  ( pos 9 , len 55 ) 
(0 0, 0 10, 10 10, 10 0, 0 0),(3 3, 3 7, 7 7, 7 3, 3 3)

<强>2。如果 1 成功,则使用 All_Polygons 的输出设置循环匹配字符串。

目标 (0 0, 0 10, 10 10, 10 0, 0 0),(3 3, 3 7, 7 7, 7 3, 3 3)

(?:\(\s*(?P<Single_Poly_All_Pts>\d+\s+\d+(?:\s*,\s*\d+\s+\d+){2,})\s*\))

这一步相当于查找所有类型的匹配项。它应该匹配单个多边形所有点的连续值,在 Single_Poly_All_Pts 中返回。组字符串。

这将为您提供这 2 个单独的匹配项,它们可以放入具有 2 个值字符串的临时数组中:

 **  Grp 1 [Single_Poly_All_Pts] -  ( pos 1 , len 27 ) 
0 0, 0 10, 10 10, 10 0, 0 0  

 **  Grp 1 [Single_Poly_All_Pts] -  ( pos 31 , len 23 ) 
3 3, 3 7, 7 7, 7 3, 3 3  

<强>3。如果 2 成功,则使用步骤 2 的临时数组输出设置循环匹配。
这将为您提供每个多边形的个人点。

(?P<Single_Point>\d+\s+\d+)

这又是一个循环匹配(或查找所有类型的匹配)。对于每个数组元素
(多边形),这将产生单独的点。

目标[元素 1] 0 0, 0 10, 10 10, 10 0, 0 0

 **  Grp 1 [Single_Point] -  ( pos 0 , len 3 ) 
0 0  
 **  Grp 1 [Single_Point] -  ( pos 5 , len 4 ) 
0 10  
 **  Grp 1 [Single_Point] -  ( pos 11 , len 5 ) 
10 10  
 **  Grp 1 [Single_Point] -  ( pos 18 , len 4 ) 
10 0  
 **  Grp 1 [Single_Point] -  ( pos 24 , len 3 ) 
0 0  

还有,

目标[元素 2] 3 3, 3 7, 7 7, 7 3, 3 3

 **  Grp 1 [Single_Point] -  ( pos 0 , len 3 ) 
3 3  
 **  Grp 1 [Single_Point] -  ( pos 5 , len 3 ) 
3 7  
 **  Grp 1 [Single_Point] -  ( pos 10 , len 3 ) 
7 7  
 **  Grp 1 [Single_Point] -  ( pos 15 , len 3 ) 
7 3  
 **  Grp 1 [Single_Point] -  ( pos 20 , len 3 ) 
3 3  

关于regex - 在 golang 正则表达式中获取子组的命名列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46058388/

有关regex - 在 golang 正则表达式中获取子组的命名列表的更多相关文章

  1. ruby 正则表达式 - 如何替换字符串中匹配项的第 n 个实例 - 2

    在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg

  2. ruby - RVM 使用列表[0] - 2

    是否有类似“RVMuse1”或“RVMuselist[0]”之类的内容而不是键入整个版本号。在任何时候,我们都会看到一个可能包含5个或更多ruby的列表,我们可以轻松地键入一个数字而不是X.X.X。这也有助于rvmgemset。 最佳答案 这在RVM2.0中是可能的=>https://docs.google.com/document/d/1xW9GeEpLOWPcddDg_hOPvK4oeLxJmU3Q5FiCNT7nTAc/edit?usp=sharing-知道链接的任何人都可以发表评论

  3. ruby - 简单获取法拉第超时 - 2

    有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url

  4. ruby - 从 Ruby 中的主机名获取 IP 地址 - 2

    我有一个存储主机名的Ruby数组server_names。如果我打印出来,它看起来像这样:["hostname.abc.com","hostname2.abc.com","hostname3.abc.com"]相当标准。我想要做的是获取这些服务器的IP(可能将它们存储在另一个变量中)。看起来IPSocket类可以做到这一点,但我不确定如何使用IPSocket类遍历它。如果它只是尝试像这样打印出IP:server_names.eachdo|name|IPSocket::getaddress(name)pnameend它提示我没有提供服务器名称。这是语法问题还是我没有正确使用类?输出:ge

  5. ruby - 获取模块中定义的所有常量的值 - 2

    我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

  6. ruby-on-rails - 获取 inf-ruby 以使用 ruby​​ 版本管理器 (rvm) - 2

    我安装了ruby​​版本管理器,并将RVM安装的ruby​​实现设置为默认值,这样'哪个ruby'显示'~/.rvm/ruby-1.8.6-p383/bin/ruby'但是当我在emacs中打开inf-ruby缓冲区时,它使用安装在/usr/bin中的ruby​​。有没有办法让emacs像shell一样尊重ruby​​的路径?谢谢! 最佳答案 我创建了一个emacs扩展来将rvm集成到emacs中。如果您有兴趣,可以在这里获取:http://github.com/senny/rvm.el

  7. ruby-on-rails - 如何重命名或移动 Rails 的 README_FOR_APP - 2

    当我在我的Rails应用程序根目录中运行rakedoc:app时,API文档是使用/doc/README_FOR_APP作为主页生成的。我想向该文件添加.rdoc扩展名,以便它在GitHub上正确呈现。更好的是,我想将它移动到应用程序根目录(/README.rdoc)。有没有办法通过修改包含的rake/rdoctask任务在我的Rakefile中执行此操作?是否有某个地方可以查找可以修改的主页文件的名称?还是我必须编写一个新的Rake任务?额外的问题:Rails应用程序的两个单独文件/README和/doc/README_FOR_APP背后的逻辑是什么?为什么不只有一个?

  8. Ruby 从大范围中获取第 n 个项目 - 2

    假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit

  9. ruby - rails 3 redirect_to 将参数传递给命名路由 - 2

    我没有找到太多关于如何执行此操作的信息,尽管有很多关于如何使用像这样的redirect_to将参数传递给重定向的建议:action=>'something',:controller=>'something'在我的应用程序中,我在路由文件中有以下内容match'profile'=>'User#show'我的表演Action是这样的defshow@user=User.find(params[:user])@title=@user.first_nameend重定向发生在同一个用户Controller中,就像这样defregister@title="Registration"@user=Use

  10. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

随机推荐