什么是进行URL匹配和标记提取的有效方法?

时间:2012-04-15 14:56:28

标签: c string algorithm pattern-matching go

鉴于两个字符串a = "/some/{tag}/here"b = "/some/text/here",我想要一个有效的算法来验证b是否与a定义的模式匹配,以及它是否提取相应的变量中b的一部分(即:tag = "text")。

C或Go中的实现也很受欢迎,但伪代码也可以。

7 个答案:

答案 0 :(得分:3)

了解the Knuth–Morris–Pratt string searching algorithm。应该为您提供所需的一切,包括伪代码。

答案 1 :(得分:2)

许多优秀的正则表达式工具包都可以做到这一点,但您可能需要更改模式的语法。例如,这是Python版本:

>>> import re
>>> a = re.compile("/some/(?P<pattern>.+)/here")
>>> b = "/some/text/here"
>>> a.match(b).group("pattern")
'text'

答案 2 :(得分:2)

也许你可以分开a

string[] array1 = a.Split('/');
string[] array2 = a.Split('/');
bool isEqual = (array1[2] == array2[2]);

答案 3 :(得分:1)

回答:Go标准库有一个URL parserregular expression包来帮助您。 Go不允许您在运行时命名变量,因此将答案设为tag = "text"并不合理。相反,您可能希望将结果作为结构返回,或者可能在地图中收集多个结果。大纲可能会像,

  1. 使用大括号编译与标记语法匹配的正则表达式。在程序加载时执行此操作一次。让我们称之为标记RE。
  2. 将tagRE应用于模式“a”。此匹配的结果将是要匹配的URL部分以及标记的名称。 (如果匹配失败,则模式“a”无效。)
  3. 使用结果构建和编译在真实URL中与该模式匹配的另一个正则表达式。我们称之为aRE。只要您认为将来可能需要匹配此模式,请继续使用此正则表达式。重复编译工作是没有意义的。
  4. 根据需要,可以根据需要重复其他模式的步骤2和3,或者可以在程序中使用模式。也许在切片或地图或其他东西中收集这些。我猜你也想把这些与你的应用程序中有用的东西联系起来,比如找到匹配时要执行的一些代码。
  5. 当您想要匹配的真实网址时,您可能希望首先使用网址包解析它以分离网址路径。
  6. 将aRE(或切片中的所有正则表达式)应用于路径,看看是否匹配。如果是,则返回包含a的标记名称的结果和aRE匹配的路径部分。您可以通过创建结果结构或添加到结果映射来完成此操作。
  7. 显示正则表达式构造的代码:

    package main
    
    import (
        "fmt"
        "regexp"
    )
    
    var a = "/some/{tag}/here/{and}/there"
    var aPath = `/some/bread/here/jam/there`
    
    func main() {
        tagPat := regexp.MustCompile("([^{]*){([^}]+)}")
        aMatch := tagPat.FindAllStringSubmatch(a, -1)
        if aMatch == nil {
            fmt.Println("bad pattern")
            return
        }
        aRE := ""
        matchLen := 0
        for _, m := range aMatch {
            if m[1] > "" {
                aRE += `\Q` + m[1] + `\E`
            }
            aRE += "(?P<" + m[2] + ">.*)"
            matchLen += len(m[0])
        }
        if matchLen < len(a) {
            aRE += `\Q` + a[matchLen:] + `\E`
        }
        aPat := regexp.MustCompile(aRE)
        pathMatch := aPat.FindStringSubmatch(aPath)
        if pathMatch == nil {
            fmt.Println("url doesn't match")
            return
        }
        for tx, tag := range aPat.SubexpNames()[1:] {
            fmt.Println(tag, "=", pathMatch[tx+1])
        }
    }
    

    输出:

      

    tag =面包
      和=果酱

答案 4 :(得分:1)

因此,您有一个/some/{tag}/here形式的模式字符串,并且您想确定某个其他字符串是否与该模式匹配。如果是,那么您想要提取{tag}部分。

在我看来,您可以将模式字符串分成三个部分:

"/some/"
"{tag}"
"/here"

现在,使用标准C比较函数(我想的是strncmp),检查字符串是以"/some/"开头还是以"/here"结尾。如果是,则可以轻松找到标记字符串的开头和结尾。开头是:

stringBegin = s + strlen("/some/");
length = strlen(s) - strlen("/some/") - strlen("/here");

然后复制掉子字符串很简单。

当然我的例子是使用常量字符串。但是,如果您可以轻松地拆分组件,那么您可以用变量替换常量。

答案 5 :(得分:0)

我假设你的标签不能包含斜杠。如果不是这样,那么我的解决方案就行不通 相当大的修改。

如果以上情况适用,那么您可以先将您的路径标记为一个列表,例如user1288160在他的回答中显示。我的解决方案将继续。

path := strings.Split(url, "/")

然后您可以使用简单的状态机来处理令牌。

type urlParser func([]string) (urlParser, []string, error)

// define handlers for the various tokens that do appropriate things
var parseMap map[string]urlParser

var startParse = func(ps []string) (urlParser, []string, error) {
   switch  {
   case len(ps) == 0:
      return nil, nil, errors.New("End Of Path")
   case len(ps) == 1:
     return parseMap[ps[0]], nil, nil
   case len(ps) > 1:
     return parseMap[ps[0]], ps[1:], nil
   }
}

p := startParse
var err error
for {
   // get the next step in the state machine, unparsed portion of the path
   // and any errors.
   next, rst, pErr := p(path)
   // an error means we are done.
   if pErr != nil {
     break;
   }
   // set up for our next iteration of the parse loop.
   p = next
   path = rst
   err = pErr
}

你的urlParsers将是一个闭包,用你匹配的任何东西填充一些变量。

答案 6 :(得分:0)

我们可以帮助它,我们需要背景信息。例如,构成“模式”的是什么,数字?信吗?数字和字母?允许哪些字符?

第一个场景:假设路径目标的位置是固定的,你可以这样做:

C代码:

char * string = "/some/text/here";
char * path;
char * b = "text";

if(strtok(strdup(string), "/")) {
    path = strtok(NULL, "/");
    if(!strcmp(b, path)) {
        /* Are equals. Do something.. */
    } else {
        /* ... */
    }
} else { 
    printf("Not found tag.\n");
}

第二个风景:

假设你只知道路径目标的前身,你可以这样做:

C代码:

char * string = "/some/text/here";

char *cpath,            /* Current path */ 
     *ppath   = NULL,   /* Predecessor path */
     *ptpath  = "some", /* Predecessor path target */
     *pathcmp = "text"; /* Path to compare */ 

cpath = strtok(strdup(string), "/");

 while(cpath) { 
    ppath = cpath; 
    cpath = strtok(NULL, "/");

    if(ppath && ptpath && !strcmp(ppath, ptpath)) {
        if(!strcmp(cpath, pathcmp)) {
            /* Are equals. */
        } else {
            /* ... */
        }

        break;
    }
}

这样的非常简单的案例,可以从正则表达式和URI解析中逃脱(当然,在很好的意义上)。

我希望这对你有所帮助。