Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby:按字节长度限制UTF-8字符串_Ruby_String_Utf 8_Byte_Rabbitmq - Fatal编程技术网

Ruby:按字节长度限制UTF-8字符串

Ruby:按字节长度限制UTF-8字符串,ruby,string,utf-8,byte,rabbitmq,Ruby,String,Utf 8,Byte,Rabbitmq,国家: 队列名称最多可以是255字节的UTF-8字符 在Ruby(1.93.)中,如何在字节的计数中截断UTF-8字符串而不在字符中间断裂?生成的字符串应该是符合字节限制的最长有效UTF-8字符串。这样如何: s = "δogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδo

国家:

队列名称最多可以是255字节的UTF-8字符

在Ruby(1.93.)中,如何在字节的计数中截断UTF-8字符串而不在字符中间断裂?生成的字符串应该是符合字节限制的最长有效UTF-8字符串。

这样如何:

s = "δogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδogδog"
count = 0
while true
  more_truncate = "a" + (255-count).to_s
  s2 = s.unpack(more_truncate)[0]
  s2.force_encoding 'utf-8'

  if s2[-1].valid_encoding?
    break
  else
    count += 1
  end
end

s2.force_encoding 'utf-8'
puts s2

我想我找到了一些有效的方法

def limit_bytesize(str, size)
  str.encoding.name == 'UTF-8' or raise ArgumentError, "str must have UTF-8 encoding"

  # Change to canonical unicode form (compose any decomposed characters).
  # Works only if you're using active_support
  str = str.mb_chars.compose.to_s if str.respond_to?(:mb_chars)

  # Start with a string of the correct byte size, but
  # with a possibly incomplete char at the end.
  new_str = str.byteslice(0, size)

  # We need to force_encoding from utf-8 to utf-8 so ruby will re-validate
  # (idea from halfelf).
  until new_str[-1].force_encoding('utf-8').valid_encoding?
    # remove the invalid char
    new_str = new_str.slice(0..-2)
  end
  new_str
end
用法:

>> limit_bytesize("abc\u2014d", 4)
=> "abc"
>> limit_bytesize("abc\u2014d", 5)
=> "abc"
>> limit_bytesize("abc\u2014d", 6)
=> "abc—"
>> limit_bytesize("abc\u2014d", 7)
=> "abc—d"
更新…

无活动\u支持的分解行为:

>> limit_bytesize("abc\u0065\u0301d", 4)
=> "abce"
>> limit_bytesize("abc\u0065\u0301d", 5)
=> "abce"
>> limit_bytesize("abc\u0065\u0301d", 6)
=> "abcé"
>> limit_bytesize("abc\u0065\u0301d", 7)
=> "abcéd"
>> limit_bytesize("abc\u0065\u0301d", 4)
=> "abc"
>> limit_bytesize("abc\u0065\u0301d", 5)
=> "abcé"
>> limit_bytesize("abc\u0065\u0301d", 6)
=> "abcéd"
具有主动_支持的分解行为:

>> limit_bytesize("abc\u0065\u0301d", 4)
=> "abce"
>> limit_bytesize("abc\u0065\u0301d", 5)
=> "abce"
>> limit_bytesize("abc\u0065\u0301d", 6)
=> "abcé"
>> limit_bytesize("abc\u0065\u0301d", 7)
=> "abcéd"
>> limit_bytesize("abc\u0065\u0301d", 4)
=> "abc"
>> limit_bytesize("abc\u0065\u0301d", 5)
=> "abcé"
>> limit_bytesize("abc\u0065\u0301d", 6)
=> "abcéd"

bytesize
将以字节为单位给出字符串的长度,而(只要字符串的编码设置正确)诸如slice之类的操作不会损坏字符串

一个简单的过程就是遍历字符串

s.each_char.each_with_object('') do|char, result| 
  if result.bytesize + char.bytesize > 255
    break result
  else
    result << char
  end
end
s.each_char.each_with_object('')do|char,result|
如果result.bytesize+char.bytesize>255
中断结果
其他的

结果对于Rails>=3.0,您有ActiveSupport::Multibyte::Chars限制方法

从API文档:

- (Object) limit(limit) 
将字符串的字节大小限制为不中断字符的字节数。当字符串的存储因某种原因受到限制时可用

例如:

'こんにちは'.mb_chars.limit(7).to_s # => "こん"
Rails 6将提供一个类似于
truncate,但采用字节计数而不是字符计数的函数。当然,它返回一个有效的字符串(它在多字节字符的中间不被切掉)。 摘自文件:

>> "

Without Rails

Fredrick Cheung's answer is an excellent
O(n)
starting point that inspired this
O(log n)
solution:

def limit_bytesize(str, max_bytesize)
  return str unless str.bytesize > max_bytesize

  # find the minimum index that exceeds the bytesize, then subtract 1
  just_over = (0...str.size).bsearch { |l| str[0..l].bytesize > max_bytesize }
  str[0..(just_over - 1)]
end
>“无导轨
是一个优秀的
O(n)
起点,激发了这个
O(log n)
解决方案:

def limit\u bytesize(str,max\u bytesize)
返回str,除非str.bytesize>max_bytesize
#找到超过字节大小的最小索引,然后减去1
just|over=(0…str.size).b搜索{l | str[0..l].bytesize>max|u bytesize}
str[0..(刚好超过-1)]
结束

我相信这也实现了自动的<代码> Max yByTestIs/4代码/代码>提速,在这个答案中,因为代码> BSchuest[/Po> >中间开始。

它工作,但是如果字符串是巨大的呢?一次删除一个UTF-8字符可能是非常低效的。@ Kelvin答案已经被编辑。f-8字符长度将不超过6字节,循环将很快结束。似乎不完整-
s
尚未更改。是否需要打包
s2
以获取新字符串?请记住,输出也必须是utf-8。@Kelvin抱歉……我忘了输出应该是s2。
s2[0]
似乎是结果,但它是在
ascii-8bit
编码中。如果我调用
.encode('utf-8')
我得到
编码::UnfinedConversionError
+1(仅针对警察示例:)。谷歌翻译证实了这一点。不过发音听起来很不一样。大家都知道,“组合字符”“这个问题只会发生在你身上。如果e-acute等是单个字符,则没有问题。首先,您可以通过转换为规范形式C来避免它。谢谢!有一种比线性构建字符串稍微快一点的方法,很好,如果您使用ActiveSupport>=3.0,这似乎是最好的解决方案。如果您已经分解了字符(请参见我的答案),您仍然需要使用
mb_chars.compose.limit
。+1该代码非常智能-它甚至可以通过使用
scan(/\X/)
将分解的字符拆分为grapheme集群来正确处理。