mysql-选择字符串的前10个字节

nxagd54h  于 2021-06-20  发布在  Mysql
关注(0)|答案(3)|浏览(370)

各位智者,
如何选择字符串的第一个x字节?
用例:我正在优化上传到amazon的产品描述文本,amazon通过utf8(而不是我前面提到的拉丁语1)中的字节来测量字段长度,而不是通过字符。另一方面,mysql似乎是基于字符的(e、 例如,函数left()是基于字符的,而不是基于字节的)。差别(使用英语、法语、西班牙语和德语)大约为10%,但差别很大。
有关#字节<250的字段的一些测试(详细信息:http://wiki.devliegendebrigade.nl/format_inventarisbestanden_(亚马逊)#维尔德伦特):

OK, char_length: 248,   byte length latin1: 248,   byte length utf8: 248
OK, char_length: 249,   byte length latin1: 249,   byte length utf8: 249
OK, char_length: 249,   byte length latin1: 249,   byte length utf8: 249
OK, char_length: 249,   byte length latin1: 249,   byte length utf8: 249

Not OK, char_length: 250,   byte length latin1: 250,   byte length utf8: 250
Not OK, char_length: 249,   byte length latin1: 249,   byte length utf8: 252
Not OK, char_length: 248,   byte length latin1: 248,   byte length utf8: 252
Not OK, char_length: 249,   byte length latin1: 249,   byte length utf8: 252
Not OK, char_length: 249,   byte length latin1: 249,   byte length utf8: 257

插图:

set @tekst="Jantje zag € pruimen hangen";

select
   char_length(@tekst),   # 27 characters
   length(@tekst);        # 29 bytes

select left(@tekst, 15)   # Result: "Jantje zag € pr"

# Ideally, I'm looking for something like this:

select left_bytes_utf8(@tekst, 15)   # Result: "Jantje zag € "

一种方法可能是通过一个存储过程迭代地调用自己,但我怀疑有更有效的解决方案。
已经谢谢了,祝你好运,杰伦
p、 s.:编辑问题:将2x“latin1”改为“utf8”。这实际上有点混乱:上传应该是拉丁文1,但是字段大小是用utf8以字节来度量的
p、 注:更新:这些上传是为英语,法语,西班牙语和德语亚马逊网站。人物的异国情调并不比ø' (直径),'€', 'è', 'é', 'ü' 然后呢ö'. 全部采用拉丁1编码,但多字节采用utf8。

dgjrabp2

dgjrabp21#

如何选择字符串的第一个x字节?
你真的想这么做吗?这可能(正如已经指出的那样)通过将多字节字符拆分为垃圾来破坏字符串。
amazon按字节计算字段长度
请提供这方面的证据。
这一差别大约为10%,但差别很大。
最大值可以是4的系数。表情符号和某些汉字需要4个字节的utf-8(utf8mb4)编码。
如果亚马逊用 latin1 (这与“按字节”不同),然后首先需要检查字符串是否可以用拉丁文1编码。西欧文本可以,但亚洲文本不能。当然,您可以得到“字节”,这会导致文本损坏,特别是当您截断到某个字节(而不是字符)时。

SELECT CONVERT(CONVERT(@tekst USING latin1) USING utf8) = @tekst;

如果转换有效,将返回1(true)。
那你可以用 CONVERT(@tekst USING latin1)LEFT(..., 10) 或者别的什么。
更好?
如果亚马逊有效地使用了拉丁语1,那么你就使用拉丁语1。也就是说,声明字符串:

for_amazon VARCHAR(10) CHARACTER SET latin1

和/或与 SET NAMES latin1 或者你可以有一个更大的领域,然后做 LEFT(..., 10) 其中一个将提供转换(存储前与获取时),这样您提供给amazon的字节将是拉丁文1。
注意:如果你把中文(或俄文或希腊文等)储存在专栏里,那就乱七八糟了。

nlejzf6q

nlejzf6q2#

谢谢你@amadan&@rick james!多亏了你的输入,我才想出了一个多字节安全的按字节左键函数:

CREATE DEFINER=`root`@`localhost` FUNCTION `left_byte`(
    input_string text,
    input_position integer
) RETURNS text CHARSET utf8
BEGIN

# Byte-wise left function

################################################################################ 

# 

# * multibyte-safe for characters of up to 4 bytes (=max # bytes utf8)

# * utf8 Assumed to be the general encoding

return 
ifnull
(
    ifnull
    (
        ifnull
        (
            convert(left(convert(input_string using binary), input_position) using utf8),
            convert(left(convert(input_string using binary), input_position-1) using utf8)
        ),
        convert(left(convert(input_string using binary), input_position-2) using utf8)
    ),
    convert(left(convert(input_string using binary), input_position-3) using utf8)
);    
END
6yt4nkrj

6yt4nkrj3#

SELECT CONVERT(LEFT(CONVERT(@tekst USING binary), 15) USING utf8);

只要它仍然是有效的utf-8字符串,mysql就会拒绝给你一个无效的字符串,例如,如果你剪切一个多字节字符,mysql就会给你一个无效的字符串 NULL 如果这不起作用,您可以通过省略最后一次对utf-8的重新转换来获得原始字节,但您必须自己将它们解码为有用的内容:

SELECT LEFT(CONVERT(@tekst USING binary), 15);

然而,里克·詹姆斯给出了很多好的建议;尽管只有你才能判断它与你的关系程度,以及你的特殊处境。

相关问题