Замените повторяющиеся пробелы одним пробелом в T-SQL

102

Мне нужно убедиться, что в данном поле не более одного пробела (меня не беспокоят все пробелы, только пробел) между символами.

Так

'single    spaces   only'

нужно превратить в

'single spaces only'

Ниже не будет работать

select replace('single    spaces   only','  ',' ')

поскольку это приведет к

'single  spaces  only'

Я бы предпочел использовать собственный T-SQL, а не решение на основе CLR.

Мысли?

Кристоф
источник
Вы можете сделать это с помощью замены REGEX
Raj More

Ответы:

329

Еще аккуратнее:

select string = replace(replace(replace(' select   single       spaces',' ','<>'),'><',''),'<>',' ')

Вывод:

выберите отдельные пробелы

Нил Найт
источник
6
Если вы хотите удалить пробелы в начале и в конце строки, оберните замену в LTRIM, RTRIM, и она сделает это за вас.
Нил Найт
7
Если ваша строка не содержит много знаков <или>. На мой вкус, кажется хрупким.
JohnFx
8
Поистине элегантный хак. Проголосовали. Для средней части могут использоваться любые два символа, если во входном тексте потенциально присутствует <>.
richardtallent
32
Крис, вы можете использовать непечатаемые символы ASCII, такие как CHAR (17) и CHAR (18), так как они НИКОГДА не будут во входном тексте. Все еще быстрее, чем цикл принятого ответа.
richardtallent
7
Мне пришлось действительно взглянуть на это на мгновение, чтобы понять, что вы использовали '> <', '' Нет замены пробела, но теперь, когда я понял ... это очень здорово. Мне очень понравилось предложение @richardtallent об использовании непечатаемых символов ASCII, добавленная комбинация которых дает: REPLACE (REPLACE (REPLACE (LastName, '', 'CHAR (17) CHAR (18)'), 'CHAR (18) ) CHAR (17) ',' '),' CHAR (17) CHAR (18) ',' ')
Энтони Григгс
25

Это сработает:

declare @test varchar(100)
set @test = 'this   is  a    test'

while charindex('  ',@test  ) > 0
begin
   set @test = replace(@test, '  ', ' ')
end

select @test
Джеймс Уайзман
источник
1
Оборачивание функции и изменение varchar (100) на nvarchar (max)
Кристоф
Разница между сценариями Джеймса и Нила заключается в том, что Джеймс запускает цикл while, который, по личному опыту, запускает 50 000 записей таблицы, как правило, очень медленно, поэтому вам нужно создать его как процедуру и передать запись и некоторые jobs у вас может не быть разрешения на создание новой процедуры группы. Использует Нейл на существующие функции , поскольку он использует <>, если у вас есть строка , как "release < now"тогда вы получите "release<><><<><>now", "release<<>now", "release< now", его то же самое с любой парой символов, если у вас есть один один из пары , то она будет двигаться
Memor-X
1
выполнение этого через 50k записей должно быть молниеносным, я бы рассмотрел другие проблемы, если это ваша проблема.
user3486773
17

Если вы знаете, что в строке не будет больше определенного количества пробелов, вы можете просто вложить замену:

replace(replace(replace(replace(myText,'  ',' '),'  ',' '),'  ',' '),'  ',' ')

4 замены должны исправить до 16 последовательных пробелов (16, затем 8, затем 4, затем 2, затем 1)

Если бы он мог быть значительно длиннее, вам бы пришлось сделать что-то вроде встроенной функции:

CREATE FUNCTION strip_spaces(@str varchar(8000))
RETURNS varchar(8000) AS
BEGIN 
    WHILE CHARINDEX('  ', @str) > 0 
        SET @str = REPLACE(@str, '  ', ' ')

    RETURN @str
END

Тогда просто сделай

SELECT dbo.strip_spaces(myText) FROM myTable
BradC
источник
Брэд, у меня был почти идентичный код, но ты опередил меня по почте, так что проголосуй за. Множественные вызовы REPLACE () - это хакерский прием, но если количество ожидаемых «лишних» пробелов предсказуемо и относительно невелико, он подойдет и удовлетворит требование OP не вызывать код RegEx через CLR.
richardtallent
6
update mytable
set myfield = replace (myfield, '  ',  ' ')
where charindex('  ', myfield) > 0 

Замена будет работать со всеми двойными пробелами, не нужно вводить несколько замен. Это решение на основе набора.

HLGEM
источник
Разве это не свернуло бы 4 клетки на 2?
Кристоф
Я назвал это решение в своих вопросах как не отвечающее потребностям, но спасибо.
Christoph
6

Это можно сделать рекурсивно с помощью функции:

CREATE FUNCTION dbo.RemSpaceFromStr(@str VARCHAR(MAX)) RETURNS VARCHAR(MAX) AS
BEGIN
  RETURN (CASE WHEN CHARINDEX('  ', @str) > 0 THEN
    dbo.RemSpaceFromStr(REPLACE(@str, '  ', ' ')) ELSE @str END);
END

тогда, например:

SELECT dbo.RemSpaceFromStr('some   string    with         many     spaces') AS NewStr

возвращает:

NewStr
some string with many spaces

Или решение, основанное на методе, описанном @ agdk26 или @Neil Knight (но безопаснее),
оба примера возвращают вывод выше:

SELECT REPLACE(REPLACE(REPLACE('some   string    with         many     spaces'
  , '  ', ' ' + CHAR(7)), CHAR(7) + ' ', ''), ' ' + CHAR(7), ' ') AS NewStr 
--but it remove CHAR(7) (Bell) from string if exists...

или

SELECT REPLACE(REPLACE(REPLACE('some   string    with         many     spaces'
  , '  ', ' ' + CHAR(7) + CHAR(7)), CHAR(7) + CHAR(7) + ' ', ''), ' ' + CHAR(7) + CHAR(7), ' ') AS NewStr
--but it remove CHAR(7) + CHAR(7) from string

Как это устроено: введите описание изображения здесь

Внимание:
символ / строка, используемый для замены пробелов, не должен существовать в начале или конце строки и быть автономным.

Адам Силенко
источник
1
Мне нравится идея рекурсивной функции для этого. есть что знать?
Zach Smith
5

Это несколько грубая сила, но сработает

CREATE FUNCTION stripDoubleSpaces(@prmSource varchar(max)) Returns varchar(max)
AS 
BEGIN
    WHILE (PATINDEX('%  %', @prmSource)>0)
     BEGIN
        SET @prmSource = replace(@prmSource  ,'  ',' ')
     END

    RETURN @prmSource
END

GO

-- Unit test -- 
PRINT dbo.stripDoubleSpaces('single    spaces   only')

single spaces only
JohnFx
источник
3

Вот простая функция, которую я создал для очистки любых пробелов до и после, а также нескольких пробелов в строке. Он изящно обрабатывает до 108 пробелов за один проход и столько же блоков, сколько в строке. Вы можете увеличить это количество раз в 8, добавив дополнительные строки с большими фрагментами пробелов, если вам нужно. Кажется, что он работает быстро и не вызывает никаких проблем, несмотря на его повсеместное использование в большом приложении.

CREATE FUNCTION [dbo].[fnReplaceMultipleSpaces] (@StrVal AS VARCHAR(4000)) 
RETURNS VARCHAR(4000) 
AS 
BEGIN

    SET @StrVal = Ltrim(@StrVal)
    SET @StrVal = Rtrim(@StrVal)

    SET @StrVal = REPLACE(@StrVal, '                ', ' ')  -- 16 spaces
    SET @StrVal = REPLACE(@StrVal, '        ', ' ')  -- 8 spaces
    SET @StrVal = REPLACE(@StrVal, '    ', ' ')  -- 4 spaces
    SET @StrVal = REPLACE(@StrVal, '  ', ' ')  -- 2 spaces
    SET @StrVal = REPLACE(@StrVal, '  ', ' ')  -- 2 spaces (for odd leftovers)

RETURN @StrVal

END
Роберт Петолилло
источник
1

Нашел это, когда искал ответ:

SELECT REPLACE(
        REPLACE(
             REPLACE(
                LTRIM(RTRIM('1 2  3   4    5     6'))
            ,'  ',' '+CHAR(7))
        ,CHAR(7)+' ','')
    ,CHAR(7),'') AS CleanString
where charindex('  ', '1 2  3   4    5     6') > 0

Полный ответ (с объяснением) был взят из: http://techtipsbysatish.blogspot.com/2010/08/sql-server-replace-multiple-spaces-with.html

На второй взгляд кажется, что это немного другая версия выбранного ответа.

Лаймей
источник
1

Способ # 1

Первый способ - заменить лишние пробелы между словами необычной комбинацией символов в качестве временного маркера. Затем вы можете заменить символы временных маркеров, используя функцию замены, а не цикл.

Вот пример кода, который заменяет текст в строковой переменной.

DECLARE @testString AS VARCHAR(256) = ' Test        text   with  random*        spacing. Please normalize  this spacing!';
SELECT REPLACE(REPLACE(REPLACE(@testString, ' ', '*^'), '^*', ''), '*^', ' ');

Тест времени выполнения №1: в десяти запусках этого метода замены среднее время ожидания ответов сервера составило 1,7 миллисекунды, а общее время выполнения - 4,6 миллисекунды. Тест времени выполнения № 2: Среднее время ожидания ответов сервера составляло 1,7 миллисекунды, а общее время выполнения - 3,7 миллисекунды.

Способ # 2

Второй метод не так элегантен, как первый, но также выполняет свою работу. Этот метод работает путем вложения четырех (или, возможно, более) операторов замены, которые заменяют два пробела одним пробелом.

DECLARE @testString AS VARCHAR(256) = ' Test        text   with  random*        spacing. Please normalize  this spacing!';
SELECT REPLACE(REPLACE(REPLACE(REPLACE(@testString,' ',' '),' ',' '),' ',' '),' ',' ')

Тест времени выполнения №1: в десяти запусках этого метода замены среднее время ожидания ответов сервера составило 1,9 миллисекунды, а общее время выполнения - 3,8 миллисекунды. Тест времени выполнения № 2: Среднее время ожидания ответов сервера составляло 1,8 миллисекунды, а общее время выполнения - 4,8 миллисекунды.

Способ # 3

Третий метод замены лишних пробелов между словами - использование простого цикла. Вы можете проверить лишние пробелы в цикле while, а затем использовать функцию replace, чтобы уменьшить лишние пробелы при каждой итерации цикла.

DECLARE @testString AS VARCHAR(256) = ' Test text with random* spacing. Please normalize this spacing!';
WHILE CHARINDEX(' ',@testString) > 0
SET @testString = REPLACE(@testString, ' ', ' ')
SELECT @testString

Тест времени выполнения №1: в десяти запусках этого метода замены среднее время ожидания ответов сервера составило 1,8 миллисекунды, а общее время выполнения - 3,4 миллисекунды. Тест времени выполнения № 2: Среднее время ожидания ответов сервера составляло 1,9 миллисекунды, а общее время выполнения - 2,8 миллисекунды.


источник
1

Это решение посредством множественной замены, которое работает для любых строк (не требует специальных символов, которые не являются частью строки).

declare @value varchar(max)
declare @result varchar(max)
set @value = 'alpha   beta gamma  delta       xyz'

set @result = replace(replace(replace(replace(replace(replace(replace(
  @value,'a','ac'),'x','ab'),'  ',' x'),'x ',''),'x',''),'ab','x'),'ac','a')

select @result -- 'alpha beta gamma delta xyz'
agdk26
источник
хорошая вещь, но замена абэ на топор
Адам Силенко
0

Я использую решение FOR XML PATH для замены нескольких пробелов на одно.

Идея состоит в том, чтобы заменить пробелы тегами XML. Затем разделить строку XML на фрагменты строки без тегов XML. Наконец, объединить эти строковые значения путем добавления одинарных пробелов между двумя

Вот как может быть вызвана финальная функция UDF

select dbo.ReplaceMultipleSpaces('   Sample   text  with  multiple  space     ')
Eralper
источник
0
 DECLARE @str varchar(150)
SET @str='Hello    My   name  is Jiyaul   mustafa'
Select REPLACE(REPLACE(REPLACE(@str,' ','{}'),'}{',''),'{}',' ')
Код
источник
0

Обычно я использую такой подход:

declare @s varchar(50)
set @s = 'TEST         TEST'
select REPLACE(REPLACE(REPLACE(@s,' ','[o][c]'),'[c][o]',''),'[o][c]',' ')
Мэттис Дю Туа
источник
0

Просто добавляем еще один метод-

Замена нескольких пробелов одним пробелом БЕЗ использования REPLACE в SQL Server-

DECLARE @TestTable AS TABLE(input VARCHAR(MAX));

INSERT INTO @TestTable VALUES
('HAPPY         NEWYEAR     2020'),
('WELCOME       ALL     !');

SELECT
    CAST('<r><![CDATA[' + input + ']]></r>' AS XML).value('(/r/text())[1] cast as xs:token?','VARCHAR(MAX)')
    AS Expected_Result
FROM @TestTable;

--OUTPUT
/*
Expected_Result
HAPPY NEWYEAR 2020
WELCOME ALL !
*/
Арулмоужи
источник
0

Пожалуйста, найдите код ниже

select trim(string_agg(value,' ')) from STRING_SPLIT('  single    spaces   only  ',' ')
where value<>' '

Это сработало для меня .. Надеюсь, это поможет ...

Лекнат Пандей
источник
-1

Вы можете попробовать это:

select Regexp_Replace('single    spaces   only','( ){2,}', ' ') from dual;
Картика Харисанкар
источник
DECLARE @str varchar (150) SET @ str = 'Здравствуйте, добро пожаловать в мир .net' Выберите REPLACE (REPLACE (REPLACE (@str, '', '{}'), '} {', ''), '{ } ',' ')
Код
-3
update mytable
set myfield = replace(myfield, '  ',  ' ')
where myfield like '%  %'

Попробуй это..

Генри
источник
Я назвал это решение в своих вопросах как не отвечающее потребностям, но спасибо.
Christoph