Flex Lexer 模式匹配句子分隔符/标点符号作为 URL 路径部分
Flex Lexer pattern matching sentence separator / punctuation as URL path part
我即将使用 RE-Flex(flex 兼容词法分析器)重构文本片段的空格标记器
我的词法分析器文件中有以下模式,我只列出涉及此问题的模式:
// ...
WHITESPACE rn|[ rntf]
DOMAIN "mil"|"info"|"gov"|"edu"|"biz"|"com"|"org"|"net"|"arpa"|"de"|[a-z]{2}
DIGIT [0-9]
LETTER [a-zA-Z]
SYMBOL ({LETTER}|{DIGIT})({LETTER}|{DIGIT}|"_"|"-")*
BARE_URL {SYMBOL}("."{SYMBOL})*"."{DOMAIN}
URL_PATH ([!*'();:@&=+$,/?%#_.~]|"-"|"["|"]"|{LETTER}|{DIGIT})+
%%
("." | "?" | "!" | ";")+ {
return tokenizer_base::TK_PUNCTUATION;
}
/* ... other patterns ... */
{BARE_URL} {
return tokenizer_base::TK_BARE_URL;
}
(("http"|"https"|"ftp")"://")?{BARE_URL}{URL_PATH}? {
return tokenizer_base::TK_FULL_URL;
}
/* ... */
/** Ignore the rest */
.|{WHITESPACE} {
;
}
%%
这基本上工作正常,但请考虑以下输入情况:
Please visit http://www.google.de.
上述字符串中的最后一个.
是句子分隔符,应作为TK_PUNCTUATION
标记类型返回。不幸的是,它没有,它被解释为TK_FULL_URL
令牌的一部分并返回为http://www.google.de.
.
考虑正常的正则表达式,我试图将[^!;.]
附加到TK_FULL_URL
模式中,但这不起作用。
另一个 - 在我看来是黑客 - 解决方案是分析返回的令牌的最后一个 字符,并将字符unput
回输入流(如果它与标点符号匹配)。我可以做这样的事情:
size_t last = YY_SCANNER.ptr_matcher()->size() - 1; // similar to YYleng
std::string last_str = YY_SCANNER.ptr_matcher()->text(); // similar to YYtext
try {
// Check if last character is a '.' and second-last char of type alpha
if (last_str.at(last) == '.' && ::isalpha(last_str.at(last - 1))) {
YY_SCANNER.ptr_matcher()->unput(last_str[last]);
YY_SCANNER.ptr_matcher()->less(last); // similar to YYless
}
} catch(const std::out_of_range& e) {
// we keep silent
}
到目前为止,这是有效的,但我认为这不是很优雅且容易出错。
所以我的基本问题是我是否可以以某种方式调整 urlpath 模式,以便最后一个.
不被视为 URL 路径的一部分?我知道http://www.domain.tld/foo/bar/.
是有效的,但http://www.domain.tld/foo/bar.
不是。
也许有一个简单的解决方案。欢迎任何建议。感谢您的努力!
绝对清楚你想要接受什么是非常重要的。否则,你不能写一个正则表达式来接受它,任何试图帮助你的人也不能。
请注意:以下段落中的(损坏的)URL是故意这样输入的,以便Markdown的识别算法显而易见。
http://www.domain.tld/foo/bar/. 和 http://www.domain.tld/foo/bar. 都是有效的 URL。但是 URL 识别器通常会避免匹配尾随.
(如您所见,Markdown 不会匹配它),因为在句子末尾编写 URL 的常见做法,即使像这样 http://www.domain.tld/foo?(但对于 http://www.domain.tld/foo?search,Markdown 会将?
识别为 URL 的一部分。
括号和引号也很棘手。为了继续运行示例,Markdown 将接受 URL 中的括号,如果它们是平衡的(http://foo.es/?q=(main())),但如您所见,仍然可以将 URL 放在括号内。此行为无法使用正则表达式进行模拟,因为正则表达式无法计数。
但让我们保持简单。我们可以只接受一个 URL,但如果最后一个字符在标点符号列表中,则排除它。所以最终可能会得到这样的结果:
URL_CHAR [][a-zA-Z0-9*@&=+$/?%#_~|()'"!:;.,-]
URL_FINAL [][a-zA-Z0-9*@&=+$/?%#_~|-]
URL_PATH {URL_CHAR}*{URL_FINAL}
关于字符类的说明:在字符类中,如果将其放在开头,则可以将]用作常规字符。因此[][…]
是用括号编写字符类的传统方法。-可以写成第一个或最后一个字符,所以你可以写[-…]
或[…-]
来包含破折号,但如果你也有]
,你需要把破折号放在最后,因为开头已经被占用了。所以你最终会得到[][…-]
这就是我写上述模式的方式。除了-、]和\之外,字符类中没有特殊字符。因此,您可以自由包含原本是正则表达式元字符的字符,例如|。除此之外,我尝试编写类,以便很明显第二个类中缺少哪些字符。
如果你想将http://www.domain.tld/foo/.
识别为URL(而不是更可能的 http://www.domain.tld/foo/后跟标点符号),你需要一些更复杂的东西,因为你必须对斜杠进行特殊处理。这是可以做到的,但是,正如我在开始时所说,重要的是确切地知道你想要匹配什么。
- 如何将更多文件夹添加到c++include路径
- 带有特殊路径部分的"std::filesystem::weakly_canonical"失败
- C++A*算法并不总是在路径中具有目标节点
- 从函数角度看ID到文件路径的内部与外部映射
- 如何使用url确定网站协议
- 下载URL中的所有文件
- boost xml parsingl将xml的路径作为变量发送
- 如何将部分流作为参数传递
- 使用libcurl提交批量url的正确BING Api POST url是什么
- 对于MacOS上的G++,如何添加默认的include目录/usr/local/include和默认的库搜索路径/usr
- 如何使用cppcheck处理半相对包含路径
- 在C++中设置基于操作系统的文件路径
- 基于编译器选项的编译二进制路径
- 按边长度递归搜索图中所有可行路径
- 使用变量值作为 PlaySound 中的路径
- 如何转换真实路径 CString c++
- Bazel:http_archive()中url的相对本地路径
- Flex Lexer 模式匹配句子分隔符/标点符号作为 URL 路径部分
- 从共享路径 URL 获取 IPAddress
- url的最短路径算法