【问题标题】:How to safely truncate a quoted string?如何安全地截断带引号的字符串?
【发布时间】:2018-12-30 09:43:14
【问题描述】:

我有以下字符串:

Customer sale 88% in urm 50

引用urllib.parse.quote,变成:

Customer%20sale%2088%25%20in%20urm%2050%27

然后我需要将其长度限制为最多 30 个字符,我使用 value[:30]

问题是它变成了无效的"Customer%20sale%2088%25%20in%"
最后一个 % 是引用字符串中 %20 的一部分,使其成为无效的引用字符串。

我无法控制原始字符串,最终结果需要有最大 30 的长度,所以我无法预先截断它。

什么方法可行?

【问题讨论】:

  • 你想让它给Customer%20sale%2088%25%20in删除尾随%吗?
  • 在这种情况下是的。 o但如果长度为 31,则必须删除 2 个字符。在任何情况下都应该是安全的。
  • .strip('%20') 会处理这种情况,可能不是所有情况。
  • "Customer%20sale%2088%25%20in%20urm%2050%27"[:30] 产生'Customer%20sale%2088%25%20in%2',其中有一部分%20,在这种情况下你想做什么?
  • @Ayxan,根据我的理解应该给Customer%20sale%2088%25%20in

标签: python urllib


【解决方案1】:

urllib.quote 使用RFC 3986 中定义的百分比编码。这意味着编码字符将始终采用"%" HEXDIG HEXDIG 的形式。

因此,您只需在最后两个字符中查找 % 符号,即可删除编码的任何尾随其余部分。

例如:

>>> s=quote("Customer sale 88% in urm 50")[:30]
>>> n=s.find('%', -2)
>>> s if n < 0 else s[:n]
'Customer%20sale%2088%25%20in'

【讨论】:

  • 我们如何确定有尾随部分要删除?结局被很好地划分为有效的情况呢?
  • @Ayxan 你是对的;当 % 未找到时,最后一个字符将被截断。相应地更新了答案。
  • 如果 OP 决定限制 19 个字符,这会产生 'Customer%20sale%208'(注意 2088 的尾部)。你的代码会处理这种情况吗?我们如何确定% 之后的部分是 2 个字符长?
  • 是的。有关如何指定编码,请参阅 RFC。
  • @Ayxan %2088 是一个空白字符,后跟两位数字 88。百分比编码始终是一个百分比符号,后跟两个数字。
【解决方案2】:

寻找悬空百分比标记怎么样?

value = value[:30]
if value[-1] == "%":
    value = value[:-1]
elif value[-2] == "%":
    value = value[:-2]
print(value)

【讨论】:

  • re.sub(r'%\d?\Z', '', value)
【解决方案3】:

编码后的字符串将始终采用%HH 的格式。您希望字符串长度最大为 30 个字符且编码有效。所以,可能是我能想到的最好的解决方案:

from urllib.parse import quote
string= "Customer sale 88% in urm 50"
string=quote(string)
string=string[:string[:30].rfind("%")]
print(string)

输出:

string=string[:string[:30].rfind("%")]

解决方案:

编码后,你可能会得到一个任意长度的字符串,下面一行代码就可以非常优化地实现你的需求。

 string=string[:string[:30].rfind("%")]

说明:

它首先从quoted string 中提取30 characters,然后从右端搜索%% 从右端开始的位置将用于提取字符串。瞧!!你得到了你的结果。

替代方法:

除了string=string[:string[:30].rfind("%")],你也可以这样做string=string[:string.rfind("%",0,30)]

注意:我提取字符串并将其存储回来以展示它是如何工作的,如果您不想存储,那么您可以简单地使用 print(string[:string[:30].rfind("%")]) 来显示结果

希望对您有所帮助...

【讨论】:

  • @martineau,是的,我将其提取并分配回变量“字符串”以展示示例,如果用户不想存储,那么我们可以简单地使用它打印而不是分配它显示结果。
  • @martineau print(string[:string[:30].rfind("%")]) print(string) 输出如下: Customer%20sale%2088%25%20in Customer%20sale %2088%25%20in%20urm%2050
  • 我认为这很令人困惑(显然)。此外,string 是 Python 内置模块的名称,因此最好不要将它们用作变量名。
  • @martineau,现在请检查答案...如果您不想将结果存储在新变量或相同变量中,那么您可以简单地提取所需信息并打印出来。它就像一个视图,不会分配内存。希望它澄清...
  • 该编辑不会将输出更改为Customer%20sale%2088%25%20in吗?
【解决方案4】:

如何将单个字符放在一个列表中,然后计数和剥离? 粗略的例子:

from urllib import quote

s = 'Customer sale 88% in urm 50'

res = []
for c in s:
    res.append(quote(c))

print res # ['C', 'u', 's', 't', 'o', 'm', 'e', 'r', '%20', 's', 'a', 'l', 'e', '%20', '8', '8', '%25', '%20', 'i', 'n', '%20', 'u', 'r', 'm', '%20', '5', '0']
print len(res)

current_length = 0
for item in res:
    current_length += len(item)

print current_length # 39

while current_length > 30:
    res = res[:-1]
    current_length = 0
    for item in res:
        current_length += len(item)

print "".join(res) # Customer%20sale%2088%25%20in

这样你就不会在引用字符的中间剪断了。如果您将来需要不同的长度,您只需要修改 while 循环。好吧,代码也可以变得更干净;)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-05
    • 2021-10-28
    • 2021-08-16
    • 1970-01-01
    • 2020-11-30
    • 2012-09-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多