规范化大写字符串,但保持括号中的内容相同
Normalize capitalised string but keep what's in brackets the same
我有一段文本,我希望对数据库中的字符串进行 ProperCase,但我在使用 ProperCase 存储过程时遇到了问题。
要解决以下问题,我需要我的函数来修复带有 ToUpper 的括号中的内容。我正在使用 SQL Server 2017。
我试过类似下面的方法。但问题是我有如下数据
我希望我的程序在一个我可以重用的函数中。这也需要在 2016 年工作
TEST DATA (BA1)
TEST DATA 2 (BA2)
TEST DATA 3 (BA3)
应该return
Test Data (BA1)
Test Data 2 (BA2)
Test Data 3 (BA3)
但它是 returning:
Test Data (Ba1)
Test Data 2 (Ba2)
Test Data 3 (Ba3)
有什么想法可以阻止它变成小写吗?所以我的意思是里面的内容(左括号和右括号应该保持大写或变成大写)
问题出现在括号中(它也使 A 小写)。我希望我的函数忽略括号内的文本。
IF OBJECT_ID('dbo.ProperCase') IS NOT NULL
DROP FUNCTION dbo.ProperCase
GO
CREATE FUNCTION dbo.PROPERCASE
(@str VARCHAR(8000))
RETURNS VARCHAR(8000)
AS
BEGIN
SET @str = ' ' + @str
SET @str = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( @str, ' a', ' A'), ' b', ' B'), ' c', ' C'), ' d', ' D'), ' e', ' E'), ' f', ' F'), ' g', ' G'), ' h', ' H'), ' i', ' I'), ' j', ' J'), ' k', ' K'), ' l', ' L'), ' m', ' M'), ' n', ' N'), ' o', ' O'), ' p', ' P'), ' q', ' Q'), ' r', ' R'), ' s', ' S'), ' t', ' T'), ' u', ' U'), ' v', ' V'), ' w', ' W'), ' x', ' X'), ' y', ' Y'), ' z', ' Z')
RETURN RIGHT(@str, LEN(@str) - 1)
END
GO
编辑 2
我也尝试了这里的好答案中的以下内容,但结果相同
SQL: capitalize first letter only
CREATE FUNCTION [dbo].[CapitalizeFirstLetter]
(
--string need to format
@string VARCHAR(200)--increase the variable size depending on your needs.
)
RETURNS VARCHAR(200)
AS
BEGIN
--Declare Variables
DECLARE @Index INT,
@ResultString VARCHAR(200)--result string size should equal to the @string variable size
--Initialize the variables
SET @Index = 1
SET @ResultString = ''
--Run the Loop until END of the string
WHILE (@Index <LEN(@string)+1)
BEGIN
IF (@Index = 1)--first letter of the string
BEGIN
--make the first letter capital
SET @ResultString =
@ResultString + UPPER(SUBSTRING(@string, @Index, 1))
SET @Index = @Index+ 1--increase the index
END
-- IF the previous character is space or '-' or next character is '-'
ELSE IF ((SUBSTRING(@string, @Index-1, 1) =' 'or SUBSTRING(@string, @Index-1, 1) ='-' or SUBSTRING(@string, @Index+1, 1) ='-') and @Index+1 <> LEN(@string))
BEGIN
--make the letter capital
SET
@ResultString = @ResultString + UPPER(SUBSTRING(@string,@Index, 1))
SET
@Index = @Index +1--increase the index
END
ELSE-- all others
BEGIN
-- make the letter simple
SET
@ResultString = @ResultString + LOWER(SUBSTRING(@string,@Index, 1))
SET
@Index = @Index +1--incerase the index
END
END--END of the loop
IF (@@ERROR
<> 0)-- any error occur return the sEND string
BEGIN
SET
@ResultString = @string
END
-- IF no error found return the new string
RETURN @ResultString
END
我已经尝试使用以下内容。
Create FUNCTION [dbo].[ProperCase2]
(@str VARCHAR(MAX))
RETURNS VARCHAR(8000)
AS
BEGIN
DECLARE @keysValueToSearch NVARCHAR(4000) = '('
DECLARE @untilThisCharAppears NVARCHAR(4000) = ')'
DECLARE @keysValueToSearchPattern NVARCHAR(4000) = '%' + @keysValueToSearch + '%'
DECLARE @leftString NVARCHAR(4000)
DECLARE @Length INT
DECLARE @test NVARCHAR(4000)
DECLARE @lhb NVARCHAR(4000)
SET @lhb = SUBSTRING(
@str,
PATINDEX(@keysValueToSearchPattern, @str) + LEN(@keysValueToSearch),
CHARINDEX(
@untilThisCharAppears,
@str,
PATINDEX(@keysValueToSearchPattern, @str) + LEN(@keysValueToSearch)
) -(PATINDEX(@keysValueToSearchPattern, @str) + LEN(@keysValueToSearch))
);
SET @Length = CHARINDEX(@keysValueToSearch, @str)
set @leftString= SUBSTRING(@str, 1,
CASE WHEN @Length - 1 < 0
THEN LEN(@str)
ELSE @Length - 1 END)
RETURN dbo.CapitalizeFirstLetter(@LeftString) + ' (' +@lhb + ')'
END
我收到以下错误
当我通过以下测试数据
SELECT dbo.ProperCase2('Test DBA (BA1)') AS Test1
SELECT dbo.ProperCase2('Test DBA EA1') AS Test2
(1 row affected) Msg 537, Level 16, State 3, Line 4 Invalid length
parameter passed to the LEFT or SUBSTRING function.
如果您知道您只有一组括号并且这是末尾,您可以拆分字符串,正确区分第一部分,然后 glom 返回第二部分。像这样:
BEGIN
SET @newstr = ' ' + LEFT(@str, CHARINDEX('(', @str);
SET @newstr = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( @str, ' a', ' A'), ' b', ' B'), ' c', ' C'), ' d', ' D'), ' e', ' E'), ' f', ' F'), ' g', ' G'), ' h', ' H'), ' i', ' I'), ' j', ' J'), ' k', ' K'), ' l', ' L'), ' m', ' M'), ' n', ' N'), ' o', ' O'), ' p', ' P'), ' q', ' Q'), ' r', ' R'), ' s', ' S'), ' t', ' T'), ' u', ' U'), ' v', ' V'), ' w', ' W'), ' x', ' X'), ' y', ' Y'), ' z', ' Z')
RETURN STUFF(@newstr, 1, 1, '') + RIGHT(@str, CHARINDEX('(', REVERSE(@str))
END;
注意:这是一个非常具体的答案,可以根据您陈述的输入破解您当前的功能。
一般来说,我建议您重写函数以逐个字符地循环遍历字符串,这样您就可以跟踪多个括号表达式。
您只需使用 SQL 即可,无需任何程序。
WITH
-- your input
indata(s) AS (
SELECT 'TEST DATA (BA1)'
UNION ALL SELECT 'TEST DATA 2 (BA2)'
UNION ALL SELECT 'TEST DATA 3 (BA3)'
)
,
-- add an identifier, which you need for grouping later ...
w_id AS (
SELECT
ROW_NUMBER() OVER(ORDER BY s) AS id
, *
FROM indata
)
,
-- "explode" into one row per space delimited sub-string using STRING_SPLIT() ...
words AS (
SELECT
id
,value
FROM w_id
CROSS APPLY STRING_SPLIT(s,' ')
)
,
-- check if the "value" you got begins with a left paren
-- and ends with a right paren, and proceed accordingly ...
right_case AS (
SELECT
id
, CASE WHEN LEFT(value,1) <> '(' AND RIGHT(value,1) <> ')'
THEN UPPER(LEFT(value,1))+LOWER(RIGHT(value,LEN(value)-1))
ELSE value
END AS val
FROM words
)
-- finally, re-aggregate all together ...
SELECT
STRING_AGG(val,' ') AS s
FROM right_case
GROUP BY id;
s
Test Data (BA1)
Test Data 2 (BA2)
Test Data 3 (BA3)
这不是一个理想的解决方案,但它似乎有效。我在这里使用了几个内联 table-value 函数。标量函数并不倾向于执行(任何地方)以及内联 table-value 函数,尽管 2019 支持标量内联,但您使用的是 2017.
首先,您需要获取 DelimitedSplit8K_LEAD
的副本,因为我们需要一个支持序数位置的拆分器(STRING_SPLIT
不支持)。然后我们可以使用一些窗口化的 SUM
s 来检查括号的数量。如果我们是肯定的,那么我们就在括号内,不应该应用“适当的”外壳。我还 假设 在 括号后可能有数据 ,否则这实际上更容易:这给出了以下内容:
USE Sandbox;
GO
CREATE OR ALTER FUNCTION dbo.ProperCase (@String varchar(8000))
RETURNS table
AS RETURN
WITH Split AS(
SELECT DS.ItemNumber,
DS.Item,
SUM(CASE CHARINDEX('(',DS.Item) WHEN 0 THEN 0 ELSE 1 END) OVER (ORDER BY DS.ItemNumber ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) -
ISNULL(SUM(CASE CHARINDEX(')',DS.Item) WHEN 0 THEN 0 ELSE 1 END) OVER (ORDER BY DS.ItemNumber ASC ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING),0) AS InBrackets
FROM dbo.DelimitedSplit8K_LEAD(@String,' ') DS)
SELECT STRING_AGG(CASE S.InBrackets WHEN 0 THEN STUFF(LOWER(S.Item),1,1,UPPER(LEFT(S.Item,1))) ELSE S.Item END,' ') WITHIN GROUP (ORDER BY S.ItemNumber) AS NewString
FROM Split S;
GO
SELECT *
FROM (VALUES('TEST DATA (BA1)'),
('TEST DATA 2 (BA2)'),
('TEST DATA 3 (BA3)'),
('TEST DATA 4 (BA4) TEST'))V(YourString)
CROSS APPLY dbo.ProperCase(V.YourString);
GO
我有一段文本,我希望对数据库中的字符串进行 ProperCase,但我在使用 ProperCase 存储过程时遇到了问题。
要解决以下问题,我需要我的函数来修复带有 ToUpper 的括号中的内容。我正在使用 SQL Server 2017。
我试过类似下面的方法。但问题是我有如下数据
我希望我的程序在一个我可以重用的函数中。这也需要在 2016 年工作
TEST DATA (BA1)
TEST DATA 2 (BA2)
TEST DATA 3 (BA3)
应该return
Test Data (BA1)
Test Data 2 (BA2)
Test Data 3 (BA3)
但它是 returning:
Test Data (Ba1)
Test Data 2 (Ba2)
Test Data 3 (Ba3)
有什么想法可以阻止它变成小写吗?所以我的意思是里面的内容(左括号和右括号应该保持大写或变成大写)
问题出现在括号中(它也使 A 小写)。我希望我的函数忽略括号内的文本。
IF OBJECT_ID('dbo.ProperCase') IS NOT NULL
DROP FUNCTION dbo.ProperCase
GO
CREATE FUNCTION dbo.PROPERCASE
(@str VARCHAR(8000))
RETURNS VARCHAR(8000)
AS
BEGIN
SET @str = ' ' + @str
SET @str = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( @str, ' a', ' A'), ' b', ' B'), ' c', ' C'), ' d', ' D'), ' e', ' E'), ' f', ' F'), ' g', ' G'), ' h', ' H'), ' i', ' I'), ' j', ' J'), ' k', ' K'), ' l', ' L'), ' m', ' M'), ' n', ' N'), ' o', ' O'), ' p', ' P'), ' q', ' Q'), ' r', ' R'), ' s', ' S'), ' t', ' T'), ' u', ' U'), ' v', ' V'), ' w', ' W'), ' x', ' X'), ' y', ' Y'), ' z', ' Z')
RETURN RIGHT(@str, LEN(@str) - 1)
END
GO
编辑 2
我也尝试了这里的好答案中的以下内容,但结果相同
SQL: capitalize first letter only
CREATE FUNCTION [dbo].[CapitalizeFirstLetter]
(
--string need to format
@string VARCHAR(200)--increase the variable size depending on your needs.
)
RETURNS VARCHAR(200)
AS
BEGIN
--Declare Variables
DECLARE @Index INT,
@ResultString VARCHAR(200)--result string size should equal to the @string variable size
--Initialize the variables
SET @Index = 1
SET @ResultString = ''
--Run the Loop until END of the string
WHILE (@Index <LEN(@string)+1)
BEGIN
IF (@Index = 1)--first letter of the string
BEGIN
--make the first letter capital
SET @ResultString =
@ResultString + UPPER(SUBSTRING(@string, @Index, 1))
SET @Index = @Index+ 1--increase the index
END
-- IF the previous character is space or '-' or next character is '-'
ELSE IF ((SUBSTRING(@string, @Index-1, 1) =' 'or SUBSTRING(@string, @Index-1, 1) ='-' or SUBSTRING(@string, @Index+1, 1) ='-') and @Index+1 <> LEN(@string))
BEGIN
--make the letter capital
SET
@ResultString = @ResultString + UPPER(SUBSTRING(@string,@Index, 1))
SET
@Index = @Index +1--increase the index
END
ELSE-- all others
BEGIN
-- make the letter simple
SET
@ResultString = @ResultString + LOWER(SUBSTRING(@string,@Index, 1))
SET
@Index = @Index +1--incerase the index
END
END--END of the loop
IF (@@ERROR
<> 0)-- any error occur return the sEND string
BEGIN
SET
@ResultString = @string
END
-- IF no error found return the new string
RETURN @ResultString
END
我已经尝试使用以下内容。
Create FUNCTION [dbo].[ProperCase2]
(@str VARCHAR(MAX))
RETURNS VARCHAR(8000)
AS
BEGIN
DECLARE @keysValueToSearch NVARCHAR(4000) = '('
DECLARE @untilThisCharAppears NVARCHAR(4000) = ')'
DECLARE @keysValueToSearchPattern NVARCHAR(4000) = '%' + @keysValueToSearch + '%'
DECLARE @leftString NVARCHAR(4000)
DECLARE @Length INT
DECLARE @test NVARCHAR(4000)
DECLARE @lhb NVARCHAR(4000)
SET @lhb = SUBSTRING(
@str,
PATINDEX(@keysValueToSearchPattern, @str) + LEN(@keysValueToSearch),
CHARINDEX(
@untilThisCharAppears,
@str,
PATINDEX(@keysValueToSearchPattern, @str) + LEN(@keysValueToSearch)
) -(PATINDEX(@keysValueToSearchPattern, @str) + LEN(@keysValueToSearch))
);
SET @Length = CHARINDEX(@keysValueToSearch, @str)
set @leftString= SUBSTRING(@str, 1,
CASE WHEN @Length - 1 < 0
THEN LEN(@str)
ELSE @Length - 1 END)
RETURN dbo.CapitalizeFirstLetter(@LeftString) + ' (' +@lhb + ')'
END
我收到以下错误
当我通过以下测试数据
SELECT dbo.ProperCase2('Test DBA (BA1)') AS Test1
SELECT dbo.ProperCase2('Test DBA EA1') AS Test2
(1 row affected) Msg 537, Level 16, State 3, Line 4 Invalid length parameter passed to the LEFT or SUBSTRING function.
如果您知道您只有一组括号并且这是末尾,您可以拆分字符串,正确区分第一部分,然后 glom 返回第二部分。像这样:
BEGIN
SET @newstr = ' ' + LEFT(@str, CHARINDEX('(', @str);
SET @newstr = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( @str, ' a', ' A'), ' b', ' B'), ' c', ' C'), ' d', ' D'), ' e', ' E'), ' f', ' F'), ' g', ' G'), ' h', ' H'), ' i', ' I'), ' j', ' J'), ' k', ' K'), ' l', ' L'), ' m', ' M'), ' n', ' N'), ' o', ' O'), ' p', ' P'), ' q', ' Q'), ' r', ' R'), ' s', ' S'), ' t', ' T'), ' u', ' U'), ' v', ' V'), ' w', ' W'), ' x', ' X'), ' y', ' Y'), ' z', ' Z')
RETURN STUFF(@newstr, 1, 1, '') + RIGHT(@str, CHARINDEX('(', REVERSE(@str))
END;
注意:这是一个非常具体的答案,可以根据您陈述的输入破解您当前的功能。
一般来说,我建议您重写函数以逐个字符地循环遍历字符串,这样您就可以跟踪多个括号表达式。
您只需使用 SQL 即可,无需任何程序。
WITH
-- your input
indata(s) AS (
SELECT 'TEST DATA (BA1)'
UNION ALL SELECT 'TEST DATA 2 (BA2)'
UNION ALL SELECT 'TEST DATA 3 (BA3)'
)
,
-- add an identifier, which you need for grouping later ...
w_id AS (
SELECT
ROW_NUMBER() OVER(ORDER BY s) AS id
, *
FROM indata
)
,
-- "explode" into one row per space delimited sub-string using STRING_SPLIT() ...
words AS (
SELECT
id
,value
FROM w_id
CROSS APPLY STRING_SPLIT(s,' ')
)
,
-- check if the "value" you got begins with a left paren
-- and ends with a right paren, and proceed accordingly ...
right_case AS (
SELECT
id
, CASE WHEN LEFT(value,1) <> '(' AND RIGHT(value,1) <> ')'
THEN UPPER(LEFT(value,1))+LOWER(RIGHT(value,LEN(value)-1))
ELSE value
END AS val
FROM words
)
-- finally, re-aggregate all together ...
SELECT
STRING_AGG(val,' ') AS s
FROM right_case
GROUP BY id;
s
Test Data (BA1)
Test Data 2 (BA2)
Test Data 3 (BA3)
这不是一个理想的解决方案,但它似乎有效。我在这里使用了几个内联 table-value 函数。标量函数并不倾向于执行(任何地方)以及内联 table-value 函数,尽管 2019 支持标量内联,但您使用的是 2017.
首先,您需要获取 DelimitedSplit8K_LEAD
的副本,因为我们需要一个支持序数位置的拆分器(STRING_SPLIT
不支持)。然后我们可以使用一些窗口化的 SUM
s 来检查括号的数量。如果我们是肯定的,那么我们就在括号内,不应该应用“适当的”外壳。我还 假设 在 括号后可能有数据 ,否则这实际上更容易:这给出了以下内容:
USE Sandbox;
GO
CREATE OR ALTER FUNCTION dbo.ProperCase (@String varchar(8000))
RETURNS table
AS RETURN
WITH Split AS(
SELECT DS.ItemNumber,
DS.Item,
SUM(CASE CHARINDEX('(',DS.Item) WHEN 0 THEN 0 ELSE 1 END) OVER (ORDER BY DS.ItemNumber ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) -
ISNULL(SUM(CASE CHARINDEX(')',DS.Item) WHEN 0 THEN 0 ELSE 1 END) OVER (ORDER BY DS.ItemNumber ASC ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING),0) AS InBrackets
FROM dbo.DelimitedSplit8K_LEAD(@String,' ') DS)
SELECT STRING_AGG(CASE S.InBrackets WHEN 0 THEN STUFF(LOWER(S.Item),1,1,UPPER(LEFT(S.Item,1))) ELSE S.Item END,' ') WITHIN GROUP (ORDER BY S.ItemNumber) AS NewString
FROM Split S;
GO
SELECT *
FROM (VALUES('TEST DATA (BA1)'),
('TEST DATA 2 (BA2)'),
('TEST DATA 3 (BA3)'),
('TEST DATA 4 (BA4) TEST'))V(YourString)
CROSS APPLY dbo.ProperCase(V.YourString);
GO