字符串长度截断,但不允许截断单词
Posted
技术标签:
【中文标题】字符串长度截断,但不允许截断单词【英文标题】:String truncate on length, but no chopping up of words allowed 【发布时间】:2011-10-02 19:08:13 【问题描述】:我想将 mysql 中的字符串字段长度限制在一定长度,但我不希望发生任何切词。
当我这样做时:
SELECT SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, 28)
我得到这个作为输出:
Business Analist met focus o
但我愿意
Business Analist met focus
如何执行 28 个字符的限制,但又能防止切词?当然,[在此处插入选择的编程语言]很容易;-),但我想知道在 MYSQL 中是否可以通过简单的语句来实现。
【问题讨论】:
您正在 MySQL 中寻找“自动换行”。有点。 这里需要逻辑。换句话说,您需要一个 if 语句。如果 MySQL 支持 if,则使用 that,否则,没办法 我认为这对 mysql 来说是相当昂贵的操作。只需在您使用的任何编程语言中砍掉这个词并在以后摆脱它。 @keymone 并非如此,请参阅sitepoint.com/mysql-mistakes-php-developers 的第 5 点(5. 优先使用 PHP 而不是 SQL) @bicycle 在你的 PHP 中实现 AVG 和做子字符串是有区别的。很有可能,如果您正在执行子字符串,则无论如何您都需要在 php 中执行其他更复杂的操作。 【参考方案1】:如何在空格上分割:
SELECT SUBSTRING_INDEX('Business Analist met focus op wet- en regelgeving',' ',4)
会回来
Business Analist met focus
【讨论】:
【参考方案2】:让@str
成为您的字符串,@len
是要剪切的初始位置。那么必要的步骤可能是:
取@str
最左边的@len
字符。
反转子串。
找到反转子串中第一个空格的位置。
从该位置减去1
。但是如果没有找到空格,就让位置保持0
。
从@len
中减去找到的位置,并将其命名为cutpos
。
将@str
的第一个(最左边)cutpos
字符作为str1
,将所有其他字符(从cutpos+1
开始)作为str2
。
SELECT
LEFT(str, cutpos) AS str1,
SUBSTRING(str, cutpos + 1) AS str2
FROM (
SELECT
@str AS str,
@len - IFNULL(NULLIF(LOCATE(' ', REVERSE(LEFT(@str, @len))), 0) - 1, 0) AS cutpos
) s
【讨论】:
【参考方案3】:非常有趣的问题。我是这样做的:
//gets initial string - use 29 instead of 28 to see if the 29th character is a space
SELECT SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, 29)
//inverts the string, so we can get the first
SELECT REVERSE( SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, 29))
// find the charindex of the first space (last space in the string not reversed)
SELECT CHARINDEX(' ', REVERSE( SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, 29)))
// get the substring from the first (last) space
SELECT SUBSTRING(REVERSE( SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, 29)), CHARINDEX(' ', REVERSE( SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, 29))), 29)
// reverse the string again to unfold it.
SELECT REVERSE(SUBSTRING(REVERSE( SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, 29)), CHARINDEX(' ', REVERSE( SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, 29))), 29))
// to try different lengths...
DECLARE @size int
select @size = 24
SELECT REVERSE(SUBSTRING(REVERSE( SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, @size)),
CHARINDEX(' ', REVERSE( SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, @size))), @size))
【讨论】:
charindex 不是有效的 mysql 函数。它应该是 LOCATE 。顺便说一句,这应该是最好的答案。 这对我有用,但我必须将 CHARINDEX 更改为 LOCATE【参考方案4】:在 SQL 中它会是...
select Substring('Business Analist met focus op wet- en regelgeving', 0 , 28 + 2 - CharIndex(' ', REVERSE(SUBSTRING('Business Analist met focus op wet- en regelgeving', 0, 28 + 1 )),0))
我不知道这些功能在MYSQL中是否都可用
编辑:我认为 MYSQL 用“Locate”替换“CharIndex”
【讨论】:
【参考方案5】:以纳尼安的回答为基础,这是一个适用于两个字段 (a.product,a.descr) 的回答,其中在字符串被截断时添加了“...”。 a.descr 也可以为空。
IF (
CHARACTER_LENGTH(
IF(
a.descr = '',
a.product,
CONCAT_WS(' - ',a.product,a.descr)
)
)>35,
IF(
a.descr = '',
CONCAT(
REVERSE(SUBSTRING(REVERSE( SUBSTRING(a.product, 1, 35)), locate(' ', REVERSE( SUBSTRING(a.product, 1, 35))), 35)),
'...'
),
CONCAT(
REVERSE(SUBSTRING(REVERSE( SUBSTRING(CONCAT_WS(' - ',a.product,a.descr), 1, 35)), locate(' ', REVERSE( SUBSTRING(CONCAT_WS(' - ',a.product,a.descr), 1, 35))), 35)),
'...'
)
),
CONCAT_WS(' - ',a.product,a.descr)
)
我需要这样的东西,所以我添加了它。可能会帮助别人。
【讨论】:
是不是你在 3 小时前否决了我的回答?如果是这样,如果您详细说明您的原因,我将不胜感激。顺便说一句,当您检查开头的长度时,您正在验证descr
是否为空,并根据此情况单独检查product
的长度或以-
分隔的两列的长度。但是稍后,当您真正找到要剪切的位置时,您不再检查descr
是否为空。我认为,有时这可能不会导致最精确的切割。
确实如此,好点。我刚刚调整了一下。是的,我对你投了反对票,因为另一个答案在没有太多定制的情况下更容易实现。不过应该调整它,因为 charindex 不是有效的 mysql 方法,而问题是关于 mysql。应该改为定位。
但不包括在指定长度内找不到空格的情况。事实上,你的也没有。不过,我意识到省略这种情况可能会使该解决方案看起来更容易。无论哪种方式,感谢您解释您的反对意见!【参考方案6】:
@Andriy M. 我非常喜欢你的回答 :) 无论如何,我在我的数据库上发现,如果您像这样更改第 2 行和第 3 行,效果会更好:
SELECT
IF(LENGTH(str)<=@len,str,LEFT(str, cutpos)) AS str1,
IF(LENGTH(str)<=@len,'',SUBSTRING(str, cutpos + 1)) AS str2
FROM (
SELECT
@str AS str,
@len - IFNULL(NULLIF(LOCATE(' ', REVERSE(LEFT(@str, @len))), 0) - 1, 0) AS cutpos
FROM @table
) s
不知道是我的错还是什么,但另一方面它有时会在第一个字母的长度为
我给你发布一个工作示例:
CREATE TABLE `test` (
`sometext` varchar(65)
);
INSERT INTO `test` (`sometext`) VALUES
('Firs strin'),
('Alll right'),
('third string'),
('fourth string'),
('a longer example string'),
('Supercalifragilisticexpialidocious');
SELECT
IF(LENGTH(str)<=12,str,LEFT(str, cutpos)) AS str1,
IF(LENGTH(str)<=12,'',SUBSTRING(str, cutpos + 1)) AS str2
FROM (
SELECT
sometext AS str,
12 - IFNULL(NULLIF(LOCATE(' ', REVERSE(LEFT(sometext, 12))), 0) - 1, 0) AS cutpos
FROM test
) s
这是一个使用您的原始代码的不工作示例:
SELECT
LEFT(str, cutpos) AS str1,
SUBSTRING(str, cutpos + 1) AS str2
FROM (
SELECT
sometext AS str,
12 - IFNULL(NULLIF(LOCATE(' ', REVERSE(LEFT(sometext,12))), 0) - 1, 0) AS cutpos
FROM test
) s
我不确定这是不是 utf8 问题,或者我只是误解了您的代码,或者其他什么...
【讨论】:
【参考方案7】:简单功能:
DROP FUNCTION IF EXISTS fn_maxlen;
delimiter //
CREATE FUNCTION fn_maxlen(s TEXT, maxlen INT) RETURNS VARCHAR(255)
BEGIN
RETURN LEFT(s, maxlen - LOCATE(' ', REVERSE(LEFT(s, maxlen))));
END//
delimiter ;
用途:
SELECT fn_maxlen('Business Analist met focus op wet- en regelgeving', 28);
【讨论】:
【参考方案8】:似乎人们不阅读mysql手册:
原文:SELECT SUBSTRING('Business Analist met focus op wet- en regelgeving', 1, 28)
给出断句。
修改:SELECT SUBSTRING_INDEX('Business Analist met focus op wet- en regelgeving', ' ' , 4)
给出完整的单词
SUBSTRING_INDEX(string, delimiter, number)
将根据找到分隔符的次数截断字符串。
让你的分隔符成为一个空格,你只会得到整个单词。所以:
SUBSTRING_INDEX( LEFT('Business Analist met focus op wet- en regelgeving',28), ' ' , 4)
应该这样做。
【讨论】:
似乎有些人不假设通用输入......答案应该适用于任意数量的单词,而不仅仅是 4 个!无论如何,SUBSTRING_INDEX 函数很有趣。以上是关于字符串长度截断,但不允许截断单词的主要内容,如果未能解决你的问题,请参考以下文章