a = "/some/{tag}/here"
2 つの文字列を考えると、変数 (つまり: ) で定義されたパターンに一致するかどうか、および一致b = "/some/text/here"
するかどうかを検証する効率的なアルゴリズムが必要です。b
a
b
tag = "text"
C や Go での実装も歓迎ですが、疑似コードでも問題ありません。
a = "/some/{tag}/here"
2 つの文字列を考えると、変数 (つまり: ) で定義されたパターンに一致するかどうか、および一致b = "/some/text/here"
するかどうかを検証する効率的なアルゴリズムが必要です。b
a
b
tag = "text"
C や Go での実装も歓迎ですが、疑似コードでも問題ありません。
Knuth–Morris–Pratt 文字列検索アルゴリズムについて読んでください。疑似コードを含め、必要なものはすべて提供する必要があります。
多くの優れた正規表現ツールキットでこれを行うことができますが、パターンの構文を変更する必要がある場合があります。たとえば、Python のバージョンは次のとおりです。
>>> import re
>>> a = re.compile("/some/(?P<pattern>.+)/here")
>>> b = "/some/text/here"
>>> a.match(b).group("pattern")
'text'
たぶん、あなたは分割することができますa
string[] array1 = a.Split('/');
string[] array2 = a.Split('/');
bool isEqual = (array1[2] == array2[2]);
したがって、フォームのパターン文字列があり、/some/{tag}/here
他の文字列がそのパターンに一致するかどうかを判断する必要があります。もしそうなら、あなたはその{tag}
部分を抽出したいと思います。
パターン文字列を3つの部分に分割できるようです。
"/some/"
"{tag}"
"/here"
ここで、標準のC比較関数(私はのようなものを考えています)を使用して、文字列がで始まり、で終わるstrncmp
かどうかを確認します。含まれている場合は、タグ文字列の最初と最後を簡単に見つけることができます。始まりは:"/some/"
"/here"
stringBegin = s + strlen("/some/");
length = strlen(s) - strlen("/some/") - strlen("/here");
次に、その部分文字列をコピーするだけです。
もちろん、私の例は定数文字列を使用しています。ただし、コンポーネントを簡単に分割できる場合は、定数の代わりに変数を使用できます。
Go の回答: Go 標準ライブラリには、役立つURL パーサーと正規表現パッケージがあります。Go では実行時に変数に名前を付けることはできないため、答えを as として取得することtag = "text"
はあまり意味がありません。代わりに、結果を構造体として返したり、複数の結果をマップに収集したりすることができます。アウトラインは次のようになります。
正規表現の構成を示すコード:
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 = パン
and = ジャム
私たちはそれを助けることができるので、背景情報が必要です。たとえば、「パターン」、数字を構成するものは何ですか?手紙?数字と文字?どの文字が許可されていますか?
最初のシーン:パスターゲットの位置が固定されていると仮定すると、次のように実行できます。
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");
}
2番目の風景:
パスターゲットの前身だけを知っていると仮定すると、次のようなことができます。
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解析から逃れることができます(もちろん、当然のことながら)。
これがお役に立てば幸いです。
タグにスラッシュを含めることはできないと思います。そうでない場合、私のソリューションはかなりの変更なしでは機能しません。
ただし、上記が当てはまる場合は、最初にパスをリストにトークン化できます。私の解決策は行きます。
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 は、一致したものを変数に取り込むクロージャーになります。