将带有百分号编码的QUrl转换为字符串

9

我使用用户输入的 URL 作为文本来初始化 QUrl 对象。后来,我想将 QUrl 转换回字符串以显示它,并使用正则表达式进行检查。只要用户不输入任何百分号编码的 URL,这个方法就可以正常工作。

为什么以下示例代码无法正常工作?

qDebug() << QUrl("http://test.com/query?q=%2B%2Be%3Axyz%2Fen").toDisplayString(QUrl::FullyDecoded); 

它只是简单地不解码任何百分号编码的字符。它应该打印 "http://test.com/query?q=++e:xyz/en",但实际上它打印的是 "http://test.com/query?q=%2B%2Be%3Axyz%2Fen"
我还尝试了很多其他方法,比如 fromUserInput(),但我无法在 Qt5.3 中使代码正确工作。
有人能向我解释如何做以及为什么上面的代码不起作用(即使用 QUrl::FullyDecoded 时也不能显示解码后的 URL)吗?
更新:
在得到 fromPercentEncoding() 提示后,我尝试了以下代码:
QUrl UrlFromUserInput(const QString& input)
{
   QByteArray latin = input.toLatin1();
   QByteArray utf8 = input.toUtf8();
   if (latin != utf8)
   {
      // URL string containing unicode characters (no percent encoding expected)
      return QUrl::fromUserInput(input);
   }
   else
   {
      // URL string containing ASCII characters only (assume possible %-encoding)
      return QUrl::fromUserInput(QUrl::fromPercentEncoding(input.toLatin1()));
   }
}

这个功能允许用户输入Unicode URL和百分号编码的URL,可以对这两种URL进行解码以进行显示/匹配。但是,在QWebView中无法使用百分号编码的URL... web服务器会有不同的响应(返回不同的页面)。所以,显然QUrl :: fromPercentEncoding()并不是一个干净的解决方案,因为它实际上改变了URL。在上述函数中,我可以创建两个QUrl对象...一个直接构建,一个使用fromPercentEncoding()构建,对于QWebView使用第一个,只用于显示/匹配的使用后者...但这似乎很荒谬。

你的意思是,“为什么它不工作”?你期望它打印什么? - peppe
类似问题 - https://dev59.com/MFPTa4cB1Zd3GeqPmMbk#4815567 - sashoalm
1
如果您在这里找不到解决方案,只需在interest@qt-project.org邮件列表上发布一封电子邮件。QUrl维护者在那里非常活跃。 - peppe
3个回答

18

#结论

我进行了一些研究,目前的结论是:荒谬

QUrl::fromPercentEncoding() 是正确的方法,OP在UPDATE部分所做的应该成为标题中问题的接受答案。

我认为Qt的文档QUrl::toDisplayString有点误导:

"返回URL的人类可读字符串表示形式。输出可以通过传递带选项的标志进行自定义。选项RemovePassword始终启用,因为密码不应向用户显示。

实际上它并没有声称具有任何解码能力,这里的文档对它的行为不清楚。但至少密码部分是正确的。我在Gitorious上找到了一些线索:

"添加QUrl ::toDisplayString(),它是没有密码的toString()。并修复toString()的文档,其中说这是用于向人类显示的方法,而这从来没有成立过。"


#测试代码 为了区分不同函数的解码能力,以下代码已在Qt 5.2.1上进行了测试(尚未在Qt 5.3上测试!)

QString target(/*path*/);

QUrl url_path(target);
qDebug() << "[Original String]:" << target;
qDebug() << "--------------------------------------------------------------------";
qDebug() << "(QUrl::toEncoded)          :" << url_path.toEncoded(QUrl::FullyEncoded);
qDebug() << "(QUrl::url)                :" << url_path.url();
qDebug() << "(QUrl::toString)           :" << url_path.toString(); 
qDebug() << "(QUrl::toDisplayString)    :" << url_path.toDisplayString(QUrl::FullyDecoded);
qDebug() << "(QUrl::fromPercentEncoding):" << url_path.fromPercentEncoding(target.toUtf8());

P.S. QUrl::urlQUrl::toString 的同义词。


[情况1]:当目标路径为"%_%"时(测试编码功能):

[Original String]: "%_%" 
-------------------------------------------------------------------- 
(QUrl::toEncoded)          : "%25_%25" 
(QUrl::url)                : "%25_%25" 
(QUrl::toString)           : "%25_%25" 
(QUrl::toDisplayString)    : "%25_%25" 
(QUrl::fromPercentEncoding): "%_%" 

[案例2]: 当目标路径="Meow !"测试编码功能)时:

[Original String]: "Meow !" 
-------------------------------------------------------------------- 
(QUrl::toEncoded)          : "Meow%20!" 
(QUrl::url)                : "Meow !" 
(QUrl::toString)           : "Meow !" 
(QUrl::toDisplayString)    : "Meow%20!" // "Meow !" when using QUrl::PrettyDecoded mode
(QUrl::fromPercentEncoding): "Meow !" 

[案例3]: 当目标路径 = "Meow|!"(测试编码功能):

[Original String]: "Meow|!" 
-------------------------------------------------------------------- 
(QUrl::toEncoded)          : "Meow%7C!" 
(QUrl::url)                : "Meow%7C!" 
(QUrl::toString)           : "Meow%7C!" 
(QUrl::toDisplayString)    : "Meow|!" // "Meow%7C!" when using QUrl::PrettyDecoded mode
(QUrl::fromPercentEncoding): "Meow|!" 

[案例 4]: 当目标路径 = "http://test.com/query?q=++e:xyz/en"未进行百分号编码)时:

[Original String]: "http://test.com/query?q=++e:xyz/en" 
-------------------------------------------------------------------- 
(QUrl::toEncoded)          : "http://test.com/query?q=++e:xyz/en" 
(QUrl::url)                : "http://test.com/query?q=++e:xyz/en" 
(QUrl::toString)           : "http://test.com/query?q=++e:xyz/en" 
(QUrl::toDisplayString)    : "http://test.com/query?q=++e:xyz/en" 
(QUrl::fromPercentEncoding): "http://test.com/query?q=++e:xyz/en" 

[情况5]: 当目标路径 = "http://test.com/query?q=%2B%2Be%3Axyz%2Fen"%编码)时:

[Original String]: "http://test.com/query?q=%2B%2Be%3Axyz%2Fen" 
-------------------------------------------------------------------- 
(QUrl::toEncoded)          : "http://test.com/query?q=%2B%2Be%3Axyz%2Fen" 
(QUrl::url)                : "http://test.com/query?q=%2B%2Be%3Axyz%2Fen" 
(QUrl::toString)           : "http://test.com/query?q=%2B%2Be%3Axyz%2Fen" 
(QUrl::toDisplayString)    : "http://test.com/query?q=%2B%2Be%3Axyz%2Fen" 
(QUrl::fromPercentEncoding): "http://test.com/query?q=++e:xyz/en" 

P.S. 我也遇到了Ilya在评论中提到的错误:QUrl中加号"+"的百分比编码似乎无法正常工作


#摘要

QUrl::toDisplayString的结果不太明确。正如文档所述,必须谨慎使用QUrl::FullyDecoded模式。无论您得到什么类型的URL,请使用QUrl::toEncode进行编码,并在必要时使用QUrl::fromPercentEncoding进行显示。

至于OP中提到的QWebView中百分比编码URL的故障,需要更多详细信息进行调试。可能是使用了不同的函数和不同的模式。


#有用的资源

  1. RFC 3986(QUrl符合该标准)
  2. 编码表
  3. Gitorious上qurl.cpp的源代码

2
感谢您的详细工作。我同意在从原始字符串构建QUrl之后应用fromPercentEncoding()是正确的想法。关于有关Web服务器如何处理编码的URL的开放性问题...我在网络上找不到太多信息。使用您的处理方式应该没有问题。但显然,百分比编码并不是完全透明的,因为我用于测试的服务器明确返回了不同的页面。我认为这完全取决于服务器端脚本的编程方式。 - Silicomancer
我想知道我们是否能够为Qt问题跟踪器创建任何明智的报告/建议。 - Silicomancer
2
其实这是一个非常好的问题,尽管我认为QUrl不像其他现代浏览器的解码器那样无所不能,但这是可以理解的。在您的情况下,您是否可以只使用QString(来自用户)进行显示/匹配操作,并在QWebView需要时将其加载到QUrl中? - Tay2510

3

我不确定为什么toDisplayString(QUrl::FullyDecoded)无法工作。

经过尝试几个版本后,我发现copy.query(QUrl::FullyDecoded)确实解码了查询部分。 文档中有一个示例,以下代码确实返回了解码后的URL:

QUrl url("http://test.com/query?q=%2B%2Be%3Axyz%2Fen");
url.setQuery(url.query(QUrl::FullyDecoded), QUrl::DecodedMode);
qDebug() << url.toString();

这种方法解决问题并不是最优的,因为查询部分没有必要复制。

3

您可以使用QUrlQuery::toString(QUrl::FullyEncoded)QUrl::fromPercentEncoding()来进行此类转换。


QUrlQuery::toString()并不能帮助我,因为我要操作的是完整的URL,而不仅仅是查询部分。QUrl::fromPercentEncoding()似乎可以工作。但是我需要先将用户输入转换为Latin1(以获取QByteArray),这会导致任何Unicode用户输入都被删除。也许这是一个好的折衷方案...但仍然没有干净的解决方案,对吧? - Silicomancer
是的,我明白。您使用的Qt版本是哪个?看起来在5.0.2中解码存在问题:Percent Encoding doesn't seem to be working for '+' in QUrl - Ilya
好的,现在我明白我的回答是无用的了。我不明白为什么你需要处理unicode字符串中的“%”符号。我确信我们不应该混淆:在1字节字符串中,我们需要“%”字符,在2字节字符串中我们不需要它。 - Ilya
1
你说得对。但请理解我不知道用户在QLineEdit中输入了什么。输入可以是%编码的URL,也可以是unicode URL。都在QString中。我认为这是一个常见的问题。因此,我希望Qt提供一个函数,接受这两种类型的URL并必要时进行解码。 - Silicomancer
我认为分析和复制Google Chrome地址栏的逻辑是个好主意。由于其源代码是公开的,您可以看到其内部工作原理(它不会是使用QUrl的Qt实现,但您将看到正确的转换逻辑)。 - Ilya

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接