如何在SQL Server 2005表的NTEXT字段中找到Unicode /非ASCII字符?

时间:2009-03-26 18:15:27

标签: sql sql-server sql-server-2005

我有一个有几千行的表。描述和摘要字段是NTEXT,有时其中包含非ASCII字符。如何找到所有非ASCII字符的行?

9 个答案:

答案 0 :(得分:48)

我有时候会使用这个“演员”声明找到“奇怪的”字符

select 
    *
from 
    <Table>
where 
    <Field> != cast(<Field> as varchar(1000))

答案 1 :(得分:16)

首先构建一个包含您不感兴趣的所有字符的字符串(该示例使用0x20 - 0x7F范围,或7位不带控制字符。)每个字符都以|为前缀,以便稍后在escape子句中使用

-- Start with tab, line feed, carriage return
declare @str varchar(1024)
set @str = '|' + char(9) + '|' + char(10) + '|' + char(13)

-- Add all normal ASCII characters (32 -> 127)
declare @i int
set @i = 32
while @i <= 127
    begin
    -- Uses | to escape, could be any character
    set @str = @str + '|' + char(@i)
    set @i = @i + 1
    end

下一个代码段会搜索列表中没有的任何字符。 %匹配0个或更多字符。 []匹配[]中的一个字符,例如[abc]将匹配a,b或c。 ^否定列表,例如[^ abc]将匹配不是a,b或c的任何内容。

select *
from yourtable
where yourfield like '%[^' + @str + ']%' escape '|'

转义字符是必需的,因为否则搜索像],%或_这样的字符会弄乱LIKE表达式。

希望这很有用,感谢JohnFX对另一个答案的评论。

答案 2 :(得分:3)

从技术上讲,我认为NCHAR(1)是一个有效的ASCII字符IF&amp;只有IF UNICODE(@NChar)&lt; 256和ASCII(@NChar)= UNICODE(@NChar)虽然这可能不是你想要的。因此,这将是一个正确的解决方案:

;With cteNumbers as
(
    Select ROW_NUMBER() Over(Order By c1.object_id) as N
    From sys.system_columns c1, sys.system_columns c2
)
Select Distinct RowID
From YourTable t
    Join cteNumbers n ON n <= Len(CAST(TXT As NVarchar(MAX)))
Where UNICODE(Substring(TXT, n.N, 1)) > 255
    OR UNICODE(Substring(TXT, n.N, 1)) <> ASCII(Substring(TXT, n.N, 1))

这也应该非常快。

答案 3 :(得分:2)

这可能不是最好的解决方案,但可能是一个类似的查询:

SELECT *
FROM yourTable
WHERE yourTable.yourColumn LIKE '%[^0-9a-zA-Z]%'

将“0-9a-zA-Z”表达式替换为捕获完整ASCII集(或数据包含的子集)的内容。

答案 4 :(得分:2)

这里你去:

def download_filing(filing):
    data=None
    try:
        data=open(filing).read()
    except:
        print 'Failed to get data...'

    if data==None: return None

    headers={}

    docs=[]
    docdata={}
    intext=False  
    inheaders=False
    headerstack=['','','','','']

    for line in data.split('\n'):
        if line.strip()=='<DOCUMENT>':
            # Beginning of a new document
            docdata={'type':None,'sequence':-1,'filename':None,'description':None,'text':''}
        elif line.strip()=='</DOCUMENT>':
            # End of a documents
            docs.append(docdata)
        elif line.strip()=='<TEXT>':
            # Text block
            intext=True
        elif line.strip()=='</TEXT>':
            # End of the text block
            intext=False
        elif line.strip().startswith('<SEC-HEADER>'):
            inheaders=True
        elif line.strip().startswith('</SEC-HEADER>'):
            inheaders=False
        elif inheaders and line.strip()!='':
            # Number of tabs before desc
            level=line.find(line.strip())
            sline=line.strip().replace(':','',1)

            # Find the dictionary level
            curdict=headers
            for i in range(level):
                curdict=curdict[headerstack[i]]

            # Determine if this is a field or a another level of fields
            if sline.find('\t')!=-1:
                curdict[sline.split('\t')[0]]=sline.split('\t')[-1]
            else:
                headerstack[level]=sline
                curdict.setdefault(sline,{})

        elif intext:
            docdata['text']+=line+'\n'
        else:
            # See if this is document metadata
            for header in DOC_HEADERS:
                if line.startswith(header):
                    field=DOC_HEADERS[header]
                    docdata[field]=line[len(header):]

    return headers,docs

答案 5 :(得分:1)

我从@ CC1960的解决方案开始,但发现一个有趣的用例导致它失败。看起来SQL Server会将某些Unicode字符等同于它们的非Unicode近似值。例如,在WHERE子句中进行比较时,SQL Server认为Unicode字符“fullwidth comma”(http://www.fileformat.info/info/unicode/char/ff0c/index.htm)与标准ASCII逗号相同。

要解决此问题,让SQL Server将字符串比较为二进制。但请记住,nvarchar和varchar二进制文件不匹配(16位与8位),因此在进行二进制比较之前,需要再次将varchar转换回nvarchar:

select *
from my_table
where CONVERT(binary(5000),my_table.my_column) != CONVERT(binary(5000),CONVERT(nvarchar(1000),CONVERT(varchar(1000),my_table.my_column)))

答案 6 :(得分:1)

如果您正在寻找特定的unicode角色,可以使用下面的内容。

   select  Fieldname from 
     (
      select Fieldname,
             REPLACE(Fieldname COLLATE Latin1_General_BIN,
             NCHAR(65533) COLLATE Latin1_General_BIN,
             'CustomText123') replacedcol
      from table
     ) results where results.replacedcol like '%CustomText123%'

答案 7 :(得分:0)

我之前的回答是混淆了UNICODE /非UNICODE数据。这是一个应该适用于所有情况的解决方案,尽管我仍然遇到一些异常现象。似乎某些上标字符的非ASCII unicode字符与实际的数字字符混淆。您可以使用排序规则来解决这个问题。

希望你的数据库中已有一个数字表(它们可能非常有用),但以防万一我已经包含了部分填充代码的代码。

你也可能需要使用数值范围,因为unicode字符可以超过255。

CREATE TABLE dbo.Numbers
(
    number  INT NOT NULL,
    CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (number)
)
GO
DECLARE @i INT

SET @i = 0

WHILE @i < 1000
BEGIN
    INSERT INTO dbo.Numbers (number) VALUES (@i)

    SET @i = @i + 1
END
GO

SELECT *,
    T.ID, N.number, N'%' + NCHAR(N.number) + N'%'
FROM
    dbo.Numbers N
INNER JOIN dbo.My_Table T ON
    T.description LIKE N'%' + NCHAR(N.number) + N'%' OR
    T.summary LIKE N'%' + NCHAR(N.number) + N'%'
and t.id = 1
WHERE
    N.number BETWEEN 127 AND 255
ORDER BY
    T.id, N.number
GO

答案 8 :(得分:-1)

- 这是一种非常非常低效的方式,但应该可以 - 小桌子。它根据Itzik Ben-Gan使用辅助数字表,简单地说 - 查找第7位设置的字符。

SELECT  *
FROM    yourTable as t
WHERE   EXISTS ( SELECT *
                 FROM   msdb..Nums as NaturalNumbers
                 WHERE  NaturalNumbers.n < LEN(t.string_column)
                        AND ASCII(SUBSTRING(t.string_column, NaturalNumbers.n, 1)) > 127)