2016-03-07 57 views
2

我正在为IRC protocol abnf message format编写正则表达式。 以下是我写的一些正则表达式的一个简短例子。如何编写代码中的正则表达式

// digit  = %x30-39     ; 0-9 
// "[0-9]" 
static const std::string digit("[\x30-\x39]"); 

我用前面的定义,以形成更复杂的,这会非常复杂,速度快。当我有问题,特别是更复杂的正则表达式时,将它们组成:

// hexdigit = digit/"A"/"B"/"C"/"D"/"E"/"F" 
// "[[0-9]ABCDEF]" 
static const std::string hexdigit("[" + digit + "ABCDEF]"); 

A“hexdigit”是“数字”或“六角信”。

注意:我不在乎RFC将“hexdigit”字母(ABCDEF)定义为只是大写字母。我只是按照RFC的说法行事,我不打算改变他们的要求。

const std::regex digit(dapps::regex::digit); 
assert(std::regex_match("0", digit)); 
assert(std::regex_match("1", digit)); 
assert(std::regex_match("2", digit)); 
assert(std::regex_match("3", digit)); 
assert(std::regex_match("4", digit)); 
assert(std::regex_match("5", digit)); 
assert(std::regex_match("6", digit)); 
assert(std::regex_match("7", digit)); 
assert(std::regex_match("8", digit)); 
assert(std::regex_match("9", digit)); 
assert(!std::regex_match("10", digit)); 

在上面的代码中,匹配“数字”工作方式的目的是在ABNF。

然而, “hexdigit” 现在是非法的正则表达式语法:

[[0-9]ABCDEF] 

[0-9ABCDEF] 

相反,并试图以配合它不会工作:

const std::regex hexdigit(dapps::regex::hexdigit); 
assert(std::regex_match("0", hexdigit)); 
assert(std::regex_match("1", hexdigit)); 
assert(std::regex_match("2", hexdigit)); 
assert(std::regex_match("3", hexdigit)); 
assert(std::regex_match("4", hexdigit)); 
assert(std::regex_match("5", hexdigit)); 
assert(std::regex_match("6", hexdigit)); 
assert(std::regex_match("7", hexdigit)); 
assert(std::regex_match("8", hexdigit)); 
assert(std::regex_match("9", hexdigit)); 
assert(std::regex_match("A", hexdigit)); 
assert(std::regex_match("B", hexdigit)); 
assert(std::regex_match("C", hexdigit)); 
assert(std::regex_match("D", hexdigit)); 
assert(std::regex_match("E", hexdigit)); 
assert(std::regex_match("F", hexdigit)); 
assert(!std::regex_match("10", hexdigit)); 

结果,如果我让“数字”没有“范围选择器中的单个字符”,([ ]),那么你不能se“数字”以匹配“数字”。

我可能只是完全错误的方式,所以我的问题是: 我是否真的需要保留两个版本,一个有或没有括号,或者有一个更简单的方法来组成正则表达式。

+0

如果我正确地读你,你想捕捉十六进制数? – Saleem

+0

十六进制数字是被捕获的20个其他组成正则表达式之一,是的。但问题不在于捕获十六进制数字,而在于从更简单的复杂正则表达式组成复杂正则表达式。 –

+0

创建一个将保存“0-9”或“ABCDEF”的字符类类。实现一个方法来加入另一个字符类对象。实现一个返回正则表达式的类(在本例中添加括号)。然后你可以做一些像'std :: regex_match(“B”,digits.or(a_to_f).regexp())'。 – Amadan

回答

2

而不是合并两个字符类作为已尝试,这应该是:

[0-9ABCDEF] 

构建交替 - 即一个逻辑OR - 经由管道炭|,和支架(非分组)的加盟条件:

(?:[0-9]|[ABCDEF]) 

这种方法的好处是,你可以加入任意两个表达式这种方式,字符类或其他方式,如数字或空白:

(?:[0-9]|\s) 

因此它可以被非常普遍地应用。


小点:你可以编写[ABCDEF][A-F]和/或可以把它用的情况下不区分大小写[A-Fa-f]

+0

你认为我应该包装每个正则表达式字符串在非捕获或捕获组? 即使比较简单的数字匹配?这会在制作更复杂的作品时有所作为吗? '(?:[\ x30- \ x39])'或'([\ x30- \ x39])'vs [[x30- \ x39]' –

+2

这是一个很好的方法,唯一的问题是如果你有在连接的类中重复字符。 '[a-fa-fa-fa-f]'是无害的; '(?:[a-f])|(?:[a-f])|(?:[a-f])|(?:[a-f])可能是灾难性的。所以需要注意的是替代品是不相容的。 – Amadan

+1

@Fran如果你需要将表达式括起来,那么你应该使用一个非捕获组“(?:...)”,原因有三:1)性能 - 它们比捕获组要快一些2)如果你曾经介绍过将组捕获到您的DSL中,创建用于组合表达式的组不会妨碍您的工作,3)您的代码执行这项工作的开销可以忽略不计 – Bohemian

1

我不确定我是否读了你的问题。如果您关注的是“复制模式”常量,你可以通过做:

static const std::string digit("0-9"); 
static const std::string hexdigit(digit + "ABCDEF"); 
static const std::string digit_range("[" + digit + "]"); 
static const std::string hexdigit_range("[" + hexdigit + "]"); 

或只保留第2,而有这样一个实用程序方法(伪代码):

static const std::string digit("0-9"); 
static const std::string hexdigit(digit + "ABCDEF"); 

string range_of(string... ranges) { 
    string result = "["; 
    for each range in ranges { 
     result += range 
    } 
    result += "]"; 
    return result; 
} 

以便您可以定义不同类型的范围常量,并使用std::regex pattern(range_of(hexdigit));或者类似std::regex pattern(range_of(digit, uppercase_alphabet, normal_punctuation));

+0

此解决方案无法工作。正如我上面所说的,在你给出的例子中,你将无法匹配vs“数字”。 (std :: regex_match(“0”,std :: regex(digit)));'你在哪里定义数字为:'static const std :: string digit(“0-9”);' –

+0

我不'不明白你的意思。 'hexdigit_range'和'range_of(hexdigit)'的内容是'[0-9ABCDEF]',它们是你所期望的不是它吗? –

+0

的权利,但你将不得不维持同一个正则表达式的多个版本,这是不是最佳的,而如果你看看上面的波希米亚解决方案,你可以只用1个正则表达式。 –

-1

要获取IRC消息的一般格式v3)你可以使用this simple regexp

^\s*(:[^ \n:]*)?([A-Za-z0-9]*)([^ \n:]*)?([^ \n:]*)?([^ \n:]*)?([^ \n:]*)?([^ \n:]*)?([^ \n:]*)?(:.*)? 

demo

它可以让你的邮件内容剖析到它的部分,允许多达六种不同的参数进行匹配,且包罗万象最后一节,由之前:

+0

请注意关于downvoting原因的评论。 –