如何替换文本中具有特定模式的单词?

时间:2016-11-29 13:53:07

标签: sql sql-server

我有一个<P>Hello <IMG title="" border=0 alt="" src="files/1.JPG"></P> <P>&nbsp;</P> <P><IMG title="" border=0 alt="" src="files/folder1/2.JPG"></P> <P>&nbsp;</P> World! <P><IMG title="" border=0 alt="" src="files/folder2/files/3.JPG"></P> <P>&nbsp;</P> <P><IMG title="" border=0 alt="" src="files/4.JPG"></P> (或src)列,其中包含示例的HTML文字:

files/

现在我需要将files/new/的每个路径从files/替换为REPLACE(或转换到其他路径),但只能替换路径为files/folder1/的路径。

files/folder2/无效(我认为),因为它也会改变1.JPG4.JPG

在上面的示例中,我只需要更改 public override Cylinder Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) { context.Reader.ReadStartDocument(); Cylinder a = new Cylinder {Id = context.Reader.ReadObjectId()}; context.Reader.ReadStartDocument(); a.description.type = context.Reader.ReadString(); a.description.kind = context.Reader.ReadString(); a.description.year = (short)context.Reader.ReadInt32(); a.description.producer = context.Reader.ReadString(); context.Reader.ReadStartArray(); a.description.brands = new List<string>(); while (context.Reader.ReadBsonType() != BsonType.EndOfDocument) { a.description.brands.Add(context.Reader.ReadString()); } context.Reader.ReadEndArray(); context.Reader.ReadStartArray(); a.description.model = new Cylinder.mode(new List<string>()); while (context.Reader.ReadBsonType() != BsonType.EndOfDocument) { a.description.model.items.Add(context.Reader.ReadString()); } context.Reader.ReadEndArray(); a.description.internalproducerdesignation = context.Reader.ReadString(); a.description.origin = context.Reader.ReadString(); context.Reader.ReadEndDocument(); context.Reader.ReadStartDocument(); a.elements = new Cylinder.elem { nonspringelements = (short) context.Reader.ReadInt32(), springelements = (short) context.Reader.ReadInt32(), discelements = (short) context.Reader.ReadInt32(), magneticelements = (short) context.Reader.ReadInt32(), activeelements = (short) context.Reader.ReadInt32(), passiveelements = (short) context.Reader.ReadInt32(), totalelements = (short) context.Reader.ReadInt32() }; context.Reader.ReadEndDocument(); a.profiles = readStringArray(context); a.certifications = readStringArray(context); a.colors = readStringArray(context); a.specialfittings = readStringArray(context); a.cutdepths = (short) context.Reader.ReadInt32(); a.rareness = context.Reader.ReadString(); context.Reader.ReadStartDocument(); a.value = new Cylinder.val { @new = context.Reader.ReadString(), used = context.Reader.ReadString() }; context.Reader.ReadEndDocument(); context.Reader.ReadStartDocument(); var blawInt = context.Reader.ReadDouble(); var blawBool = context.Reader.ReadBoolean(); context.Reader.ReadEndDocument(); a.availableat = context.Reader.ReadString(); a.specialabout = context.Reader.ReadString(); context.Reader.ReadStartDocument(); a.development = new Cylinder.devel { predecessor = context.Reader.ReadString(), follower = context.Reader.ReadString() }; context.Reader.ReadEndDocument(); var objects=new List<object>(); context.Reader.ReadStartArray(); while (context.Reader.ReadBsonType() != BsonType.EndOfDocument) { objects.Add(context.Reader.ReadString()); } context.Reader.ReadEndArray(); a.media = objects.ToArray(); context.Reader.ReadEndDocument(); return a; } private static IEnumerable<string> readStringArray(BsonDeserializationContext context) { context.Reader.ReadStartArray(); var strings = new List<string>(); while (context.Reader.ReadBsonType() != BsonType.EndOfDocument) { strings.Add(context.Reader.ReadString()); } context.Reader.ReadEndArray(); return strings; } class weatherGetter { fileprivate let weatherMapBaseURL = "https://api.wunderground.com/api/" fileprivate let weatherAPIKey = "************" func getWeather(city: String) { // This is a pretty simple networking task, so the shared session will do. let session = URLSession.shared let weatherRequestURL = URL(string: "\(weatherMapBaseURL)\(weatherAPIKey)/conditions/q/FL/\(city).json")! let dataTask = session.dataTask(with: weatherRequestURL, completionHandler: { (data: Data?, response: URLResponse?, error: NSError?) in if let error = error { // Case 1: Error // We got some kind of error while trying to get data from the server. print("Error:\n\(error)") } else { do { // Try to convert that data into a Swift dictionary let dataString = String(data: data!, encoding: String.Encoding.utf8) print("Human-readable data:\n\(dataString!)") let fullArr = dataString!.characters.split{$0 == "\n"}.map(String.init) let smallArr = String(fullArr[79]).characters.split{$0 == ":"}.map(String.init) let smallerArr = String(smallArr[1]).characters.split{$0 == ","}.map(String.init) //let smallerArr2 = String(smallArr[1]).characters.split{$0 == ","}.map(String.init) //let characters = Array(smallerArr) //print(smallerArr[0]) let final = String(smallerArr[0]) //print(final) let charArr = Array(final!.characters) //print(charArr) let subarray = charArr[1...charArr.count-2] let finalNum = String(subarray) let myDouble = Double(finalNum) var myDouble2: Double = myDouble! print(myDouble2) Calculator_Calculations.sharedInstance.uvIndex = myDouble2 print(Calculator_Calculations.sharedInstance.uvIndex) //print(String(subarray)) //print(finalNum) //print(myDouble) } // Case 2: Success // We got a response from the server! //let dataString = String(data: data!, encoding: NSUTF8StringEncoding) //print("Human-readable data:\n\(dataString!)") } } as! (Data?, URLResponse?, Error?) -> Void) // The data task is set up...launch it! dataTask.resume() } } 的路径。

我该怎么办? (问题特定于sql-server)

注意:文件名/内容可能有所不同。上面的HTML只是一个例子。

3 个答案:

答案 0 :(得分:2)

按照快速方法替换nvarchar(max)字符串中的某个模式。更确切地说:代码将nvarchar(max)变量@x作为源,并将转换后的字符串写入新变量@y。但是,我只写了字符串替换的一部分 - “更新”仍然需要编码。

DECLARE @x nvarchar(max) = '<P>Hello <IMG title="" border=0 alt="" src="files/1.JPG"></P>
<P>&nbsp;</P>
<P><IMG title="" border=0 alt="" src="files/folder1/2.JPG"></P>
<P>&nbsp;</P> World!
<P><IMG title="" border=0 alt="" src="files/folder2/files/3.JPG"></P>
<P>&nbsp;</P>
<P><IMG title="" border=0 alt="" src="files/4.JPG"></P>'

DECLARE @brPos int = (SELECT CHARINDEX('</P>', @x));
DECLARE @brPosPrev int = 0;

DECLARE @srcPos int;
DECLARE @SlashPos int;
DECLARE @JPGPos int;

DECLARE @y nvarchar(max) = '';

DECLARE @xPart nvarchar(max);

WHILE (@brPos != 0)
BEGIN
  SET @xPart = SUBSTRING(@x, CASE WHEN @brPosPrev = 0 THEN @brPosPrev ELSE @brPosPrev END, @brPos-CASE WHEN @brPosPrev = 0 THEN @brPosPrev ELSE @brPosPrev END+4)

  SET @srcPos = (SELECT CHARINDEX('src="files/', @xPart))+11;
  SET @JPGPos = (SELECT CHARINDEX('.JPG', @xPart));
  SET @SlashPos = (SELECT CHARINDEX('/', @xPart, @srcPos));

  IF (@JPGPos < @SlashPos OR @SlashPos = 0)
    SET @xPart = REPLACE(@xPart, 'src="files/', 'src="files/new/');

  SET @y = @y + @xPart;

  SET @brPosPrev = @brPos + 4;
  SET @brPos = (SELECT CHARINDEX('</P>', @x, @brPosPrev));

END

SELECT @y

我在CHARINDEX调用中使用的模式也可以移动到变量 - 所以你不必使用.JPG或其他任何东西。

答案 1 :(得分:1)

我的解决方案:

DECLARE @input nvarchar(max) = 
'<P>Hello <IMG title="" border=0 alt="" src="files/zzz/1.JPG"></P>
<P>&nbsp;</P>
<P><IMG title="" border=0 alt="" src="files/2.PNG"></P>
<P>&nbsp;</P> World!
<P><IMG title="" border=0 alt="" src="files/folder2/files/3.JEPG"></P>
<P>&nbsp;</P>
<P><IMG title="" border=0 src="files/4.PNG" alt=""></P>'


DECLARE @path_old nvarchar(max) = 'files/';
DECLARE @path_new nvarchar(max) = 'files/new/';

DECLARE @i int, @j int;
DECLARE @path_len int = LEN(@path_old);
DECLARE @input_len int = LEN(@input);
DECLARE @start_location int = 1;
DECLARE @output nvarchar(max) = '';
DECLARE @p nvarchar(max);

WHILE 1 = 1 
BEGIN
    SET @i = CHARINDEX('"' + @path_old, @input, @start_location) 
    IF @i <> 0 
    BEGIN
        SET @j = CHARINDEX('"', @input, @i + 1);
        SET @p = SUBSTRING(@input, @i + @path_len + 1, @j - @i - @path_len);
        IF CHARINDEX('/', @p) = 0  
            SET @output = @output + SUBSTRING(@input, @start_location - 1, @i + 2 - @start_location) + @path_new + @p 
        ELSE
            SET @output = @output + SUBSTRING(@input, @start_location - 1, @j + 2 - @start_location);           

        SET @start_location = @j + 2    
        IF @start_location >= @input_len BREAK;
    END
    ELSE
    BEGIN
        SET @output = @output + SUBSTRING(@input, @start_location - 1, @input_len - @start_location + 2);
        BREAK;  
    END
END

PRINT @output

答案 2 :(得分:0)

方法1 - 1或2个已知文件名

如果您只需要替换1.JPG4.JPG的路径,那么您可以编写UPDATE语句:

UPDATE t
    SET html = REPLACE(REPLACE(html, 'src="files/4.JPG"', 'src="files/new/4.JPG"'), 'src="files/1.JPG"', 'src="files/new/1.JPG"')
FROM t
WHERE CHARINDEX('src="files/1.JPG"', html) + CHARINDEX('src="files/4.JPG"', html) > 0;

或者,如果您希望将它们分开:

UPDATE t
    SET html = REPLACE(html, 'src="files/1.JPG"', 'src="files/new/1.JPG"')
FROM t
WHERE CHARINDEX('src="files/1.JPG"', html) > 0;


UPDATE t
    SET html = REPLACE(html, 'src="files/4.JPG"', 'src="files/new/4.JPG"')
FROM t
WHERE CHARINDEX('src="files/4.JPG"', html) > 0;

方法2 - 可能很大的文件列表,其名称可以从文件系统中确定

如果您需要替换大量文件的路径,可以从文件系统中确定其文件名,请尝试以下方法:

  1. 如果需要,请启用xp_cmdshell(请参阅Enable 'xp_cmdshell' SQL Server)。

  2. 创建一个临时表来存储文件名:

    CREATE TABLE #Images(
        Image_Name VARCHAR(100) NULL
    )
    
  3. 列出所有文件。

    INSERT INTO #Images
    exec xp_cmdshell 'dir D:\Data\*.jpg /b'
    
  4. 删除NULL行以及其他不需要的内容。

    DELETE FROM #Images
    WHERE Image_Name IS NULL
    
  5. 为每个文件名生成SQL语句。

    SELECT '
        UPDATE t
            SET html = REPLACE(html, ''src="files/' + Image_Name + '"'', ''src="files/new/' + Image_Name + '"'')
        FROM t
        WHERE CHARINDEX(''src="files/' + Image_Name + '"'', html) > 0;
    '
    FROM #Images
    
  6. 现在只需复制粘贴执行上述SELECT语句的输出并执行UPDATE查询。