我有一个有几千行的表。描述和摘要字段是NTEXT,有时其中包含非ASCII字符。如何找到所有非ASCII字符的行?
答案 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)