Question

Je suis dans le processus de création d'une procédure temporaire dans SQL parce que j'ai une valeur d'un tableau qui est écrit en markdown, de sorte qu'il semble que le rendu HTML dans le navigateur web (markdown pour la conversion HTML).

Chaîne de la colonne ressembler à ceci:

Questions about **general computing hardware and software** are off-topic for Stack Overflow unless they directly involve tools used primarily for programming. You may be able to get help on [Super User](http://superuser.com/about)

Je suis actuellement en train de travailler avec le gras et l'italique du texte.Ce que cela signifie (dans le cas d'un texte en gras) J'ai besoin de remplacer impair N fois le modèle**avec<b>et même des fois avec</b>.
J'ai vu replace() mais il effectuer le remplacement sur tous les modèles de la chaîne.

Alors, Comment je peux remplacer une sous-chaîne que s'il est impair, ou seulement il est le même?

Mise à jour: Certains peuples d'étonnant à ce que les schémas, je suis en utilisant donc il suffit de prendre un coup d'oeil ici.

Un plus supplémentaire si vous le souhaitez: La démarque style de lien hypertexte lien hypertexte html n'a pas l'air si simple.

Était-ce utile?

La solution

À l'aide de laSTUFFfonction et un simpleWHILEboucle:

CREATE FUNCTION dbo.fn_OddEvenReplace(@text nvarchar(500), 
                                      @textToReplace nvarchar(10), 
                                      @oddText nvarchar(10), 
                                      @evenText nvarchar(500))
RETURNS varchar(max)
AS
BEGIN
    DECLARE @counter tinyint
    SET @counter = 1

    DECLARE @switchText nvarchar(10)
    WHILE CHARINDEX(@textToReplace, @text, 1) > 0
    BEGIN
        SELECT @text = STUFF(@text, 
                    CHARINDEX(@textToReplace, @text, 1), 
                    LEN(@textToReplace), 
                    IIF(@counter%2=0,@evenText,@oddText)),
                @counter = @counter + 1
    END
    RETURN @text
END

Et vous pouvez l'utiliser comme ceci:

SELECT dbo.fn_OddEvenReplace(column, '**', '<b>', '</b>')
FROM table

Mise à JOUR:

C'est re-écrite par SP:

CREATE PROC dbo.##sp_OddEvenReplace @text nvarchar(500), 
                                  @textToReplace nvarchar(10), 
                                  @oddText nvarchar(10), 
                                  @evenText nvarchar(10),
                                  @returnText nvarchar(500) output
AS
BEGIN
    DECLARE @counter tinyint
    SET @counter = 1

    DECLARE @switchText nvarchar(10)
    WHILE CHARINDEX(@textToReplace, @text, 1) > 0
    BEGIN
        SELECT @text = STUFF(@text, 
                    CHARINDEX(@textToReplace, @text, 1), 
                    LEN(@textToReplace), 
                    IIF(@counter%2=0,@evenText,@oddText)),
                @counter = @counter + 1
    END
    SET @returnText = @text
END
GO

Et à exécuter:

DECLARE @returnText nvarchar(500)
EXEC dbo.##sp_OddEvenReplace '**a** **b** **c**', '**', '<b>', '</b>', @returnText output

SELECT @returnText

Autres conseils

Conformément à la demande du commettant, j'ai modifié ma réponse pour exécuter une procédure stockée temporaire.J'ai laissé ma précédente réponse, comme je crois l'usage par rapport à un tableau de chaînes de caractères pour être utile aussi.

Si un compte (ou les Numéros) de la table est connu pour existe déjà avec au moins 8000 valeurs, puis la section marquée de la CTE peut être omis et le CTE de référence tally remplacé par le nom de l'actuel tableau de Pointage.

create procedure #HtmlTagExpander(
     @InString   varchar(8000) 
    ,@OutString  varchar(8000)  output
)as 
begin
    declare @Delimiter  char(2) = '**';

    create table #t( 
         StartLocation  int             not null
        ,EndLocation    int             not null

        ,constraint PK unique clustered (StartLocation desc)
    );

    with 
          -- vvv Only needed in absence of Tally table vvv
    E1(N) as ( 
        select 1 from (values
            (1),(1),(1),(1),(1),
            (1),(1),(1),(1),(1)
        ) E1(N)
    ),                                              --10E+1 or 10 rows
    E2(N) as (select 1 from E1 a cross join E1 b),  --10E+2 or 100 rows
    E4(N) As (select 1 from E2 a cross join E2 b),  --10E+4 or 10,000 rows max
    tally(N) as (select row_number() over (order by (select null)) from E4),
          -- ^^^ Only needed in absence of Tally table ^^^

    Delimiter as (
        select len(@Delimiter)     as Length,
               len(@Delimiter)-1   as Offset
    ),
    cteTally(N) AS (
        select top (isnull(datalength(@InString),0)) 
            row_number() over (order by (select null)) 
        from tally
    ),
    cteStart(N1) AS 
        select 
            t.N 
        from cteTally t cross join Delimiter 
        where substring(@InString, t.N, Delimiter.Length) = @Delimiter
    ),
    cteValues as (
        select
             TagNumber = row_number() over(order by N1)
            ,Location   = N1
        from cteStart
    ),
    HtmlTagSpotter as (
        select
             TagNumber
            ,Location
        from cteValues
    ),
    tags as (
        select 
             Location       = f.Location
            ,IsOpen         = cast((TagNumber % 2) as bit)
            ,Occurrence     = TagNumber
        from HtmlTagSpotter f
    )
    insert #t(StartLocation,EndLocation)
    select 
         prev.Location
        ,data.Location
    from tags data
    join tags prev
       on prev.Occurrence = data.Occurrence - 1
      and prev.IsOpen     = 1;

    set @outString = @Instring;

    update this
    set @outString = stuff(stuff(@outString,this.EndLocation,  2,'</b>')
                                           ,this.StartLocation,2,'<b>')
    from #t this with (tablockx)
    option (maxdop 1);
end
go

Invoquée comme ceci:

declare @InString   varchar(8000) 
       ,@OutString  varchar(8000);

set @inString = 'Questions about **general computing hardware and software** are off-topic **for Stack Overflow.';
exec #HtmlTagExpander @InString,@OutString out; select @OutString;

set @inString = 'Questions **about** general computing hardware and software **are off-topic** for Stack Overflow.';
exec #HtmlTagExpander @InString,@OutString out; select @OutString;
go

drop procedure #HtmlTagExpander;
go

Il donne en sortie:

Questions about <b>general computing hardware and software</b> are off-topic **for Stack Overflow.

Questions <b>about</b> general computing hardware and software <b>are off-topic</b> for Stack Overflow.

Une option est d'utiliser une Expression Régulière comme il en rend le remplacement de ces modèles très simples.Fonctions RegEx ne sont pas intégrées dans SQL Server, de sorte que vous devez utiliser SQL CLR, compilé par vous ou d'une bibliothèque existante.

Pour cet exemple, je vais utiliser le SQL# (SQLsharp) bibliothèque (dont je suis l'auteur), mais les fonctions RegEx sont disponibles dans la version Gratuite.

SELECT SQL#.RegEx_Replace
(
   N'Questions about **general computing hardware and software** are off-topic\
for Stack Overflow unless **they** directly involve tools used primarily for\
**programming. You may be able to get help on [Super User]\
(https://superuser.com/about)', -- @ExpressionToValidate
   N'\*\*([^\*]*)\*\*', -- @RegularExpression
   N'<b>$1</b>', -- @Replacement
   -1, -- @Count (-1 = all)
   1, - @StartAt
   'IgnoreCase' -- @RegEx options
);

Le schéma ci-dessus \*\*([^\*]*)\*\* regarde juste pour quoi que ce soit entouré de doubles astérisques.Dans ce cas, vous n'avez pas besoin de vous soucier de pair / impair.Cela signifie également que vous n'aurez pas un mal formé <b>seule balise si pour une raison quelconque il ya un supplément de ** dans la chaîne.J'ai ajouté deux autres cas de test à la chaîne d'origine:un ensemble complet de ** autour de la parole they et d'une incomparable ensemble de ** juste avant le mot programming.La sortie est:

Questions about <b>general computing hardware and software</b> are off-topicfor Stack Overflow unless <b>they</b> directly involve tools used primarily for **programming. You may be able to get help on [Super User](https://superuser.com/about)

qui se traduit par:

Des Questions sur général matériel informatique et les logiciels sont hors topicfor Débordement de Pile, à moins que ils impliquer directement les outils utilisés principalement pour: **la programmation.Vous pouvez peut-être obtenir de l'aide sur Super Utilisateur

Cette solution utilise des techniques décrites par Jeff Moden dans cet article sur la Somme problème dans SQL.Cette solution est longue, mais en faisant usage de la Bizarre De Mise À Jour dans SQL Server sur un index cluster, promet d'être beaucoup plus efficace sur de grandes séries de données de base de curseur solutions.

Mise à jour - amendé ci-dessous pour fonctionner hors d'un tableau de chaînes de caractères

En supposant l'existence d'un tableau de pointage créé de cette manière (avec au moins 8000 lignes):

create table dbo.tally (
     N int not null
    ,unique clustered (N desc)
);
go

with 
E1(N) as ( 
    select 1 from (values
        (1),(1),(1),(1),(1),
        (1),(1),(1),(1),(1)
    ) E1(N)
),                                              --10E+1 or 10 rows
E2(N) as (select 1 from E1 a cross join E1 b),  --10E+2 or 100 rows
E4(N) As (select 1 from E2 a cross join E2 b)   --10E+4 or 10,000 rows max
insert dbo.tally(N)
select row_number() over (order by (select null)) from E4;
go

et un HtmlTagSpotter la fonction définie comme ceci:

create function dbo.HtmlTagSPotter(
     @pString       varchar(8000)
    ,@pDelimiter    char(2))
returns table with schemabinding as
return
   WITH 
        Delimiter as (
        select len(@pDelimiter)     as Length,
               len(@pDelimiter)-1   as Offset
    ),
    cteTally(N) AS (
        select top (isnull(datalength(@pstring),0)) 
            row_number() over (order by (select null)) 
        from dbo.tally
    ),
    cteStart(N1) AS (--==== Returns starting position of each "delimiter" )
        select 
            t.N 
        from cteTally t cross join Delimiter 
        where substring(@pString, t.N, Delimiter.Length) = @pDelimiter
    ),
    cteValues as (
        select
             ItemNumber = row_number() over(order by N1)
            ,Location   = N1
        from cteStart
    )
    select
         ItemNumber
        ,Location
    from cteValues
go

ensuite, l'exécution de la requête SQL suivante va effectuer la substitution.Notez que la jointure interne à la fin empêche toute fuite "bizarre" des balises à partir de la conversion:

create table #t( 
     ItemNo         int             not null
    ,Item           varchar(8000)       null
    ,StartLocation  int             not null
    ,EndLocation    int             not null

    ,constraint PK unique clustered (ItemNo,StartLocation desc)
);

with data(i,s) as ( select i,s from (values
        (1,'Questions about **general computing hardware and software** are off-topic **for Stack Overflow.')
       ,(2,'Questions **about **general computing hardware and software** are off-topic **for Stack Overflow.')
          --....,....1....,....2....,....3....,....4....,....5....,....6....,....7....,....8....,....9....,....0
    )data(i,s)
),
tags as (
    select 
         ItemNo         = data.i
        ,Item           = data.s
        ,Location       = f.Location
        ,IsOpen         = cast((TagNumber % 2) as bit)
        ,Occurrence     = TagNumber
    from data
    cross apply dbo.HtmlTagSPotter(data.s,'**') f
)
insert #t(ItemNo,Item,StartLocation,EndLocation)
select 
     data.ItemNo
    ,data.Item
    ,prev.Location
    ,data.Location
from tags data
join tags prev
   on prev.ItemNo       = data.ItemNo
  and prev.Occurrence = data.Occurrence - 1
  and prev.IsOpen     = 1

union all

select 
    i,s,8001,8002
from data
;

declare @ItemNo     int
       ,@ThisStting varchar(8000);

declare @s varchar(8000);
update this
    set @s = this.Item = case when this.StartLocation > 8000
                              then this.Item
                              else stuff(stuff(@s,this.EndLocation,  2,'</b>')
                                                 ,this.StartLocation,2,'<b>')
                         end
from #t this with (tablockx)
option (maxdop 1);

select
    Item
from (
    select 
         Item
        ,ROW_NUMBER() over (partition by ItemNo order by StartLocation) as rn
    from #t
) t
where rn = 1
go

rendement:

Item
------------------------------------------------------------------------------------------------------------
Questions about <b>general computing hardware and software</b> are off-topic **for Stack Overflow.
Questions <b>about </b>general computing hardware and software<b> are off-topic </b>for Stack Overflow.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top