C# 从C中的字符串中删除字节顺序标记#
我读过类似的文章,但他们没有回答我的问题 在C#中,我有一个从WebClient.DownloadString获取的字符串。我已经尝试将client.Encoding设置为新的UTF8Encoding(false),但这没有什么区别-我仍然在结果字符串的开头使用UTF-8的字节顺序标记。我需要删除它(用LINQ解析生成的XML),并希望在内存中这样做 所以我有一个以\x00EF\x00BB\x00BF开头的字符串,如果它存在,我想删除它。现在我正在使用C# 从C中的字符串中删除字节顺序标记#,c#,string,encoding,C#,String,Encoding,我读过类似的文章,但他们没有回答我的问题 在C#中,我有一个从WebClient.DownloadString获取的字符串。我已经尝试将client.Encoding设置为新的UTF8Encoding(false),但这没有什么区别-我仍然在结果字符串的开头使用UTF-8的字节顺序标记。我需要删除它(用LINQ解析生成的XML),并希望在内存中这样做 所以我有一个以\x00EF\x00BB\x00BF开头的字符串,如果它存在,我想删除它。现在我正在使用 if (xml.StartsWith(By
if (xml.StartsWith(ByteOrderMarkUtf8))
{
xml = xml.Remove(0, ByteOrderMarkUtf8.Length);
}
但这感觉不对。我尝试过各种各样的流、GetBytes和编码代码,但都不管用。谁能提供从字符串中剥离BOM表的“正确”算法
谢谢大家! 如果变量xml的类型为字符串,则说明您已经做错了什么-在字符串中,BOM表不应表示为三个单独的字符,而应表示为单个代码点。不要使用DownloadString,而是使用DownloadData并解析字节数组。XML解析器应该识别BOM本身,并跳过它(自动检测文档编码为UTF-8除外)。将字节缓冲区(通过下载数据)传递到
字符串编码.UTF8.GetString(byte[])
以获取字符串,而不是将缓冲区作为字符串下载。您当前的方法可能有更多的问题,而不仅仅是修剪字节顺序标记。除非像我在这里建议的那样正确解码,否则unicode字符可能会被误解,导致字符串损坏
编辑:Martin的答案更好,因为它避免了为仍然需要解析的XML分配整个字符串。我给出的答案最适用于不需要解析为XML的一般字符串。我有一些不正确的测试数据,这导致了一些混乱。根据调查,我发现这是有效的:
private readonly string _byteOrderMarkUtf8 =
Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
public string GetXmlResponse(Uri resource)
{
string xml;
using (var client = new WebClient())
{
client.Encoding = Encoding.UTF8;
xml = client.DownloadString(resource);
}
if (xml.StartsWith(_byteOrderMarkUtf8, StringComparison.Ordinal))
{
xml = xml.Remove(0, _byteOrderMarkUtf8.Length);
}
return xml;
}
正确设置客户端编码属性可将BOM表减少为单个字符。但是,XDocument.Parse仍然不会读取该字符串。这是我迄今为止最干净的版本。这也适用
int index = xmlResponse.IndexOf('<');
if (index > 0)
{
xmlResponse = xmlResponse.Substring(index, xmlResponse.Length - index);
}
int index=xmlResponse.IndexOf(“我有一个非常类似的问题(我需要解析一个XML文档,该文档表示为一个字节数组,该数组的开头有一个字节顺序标记)。我使用Martin对其答案的一个注释来找到解决方案。我使用了我拥有的字节数组(而不是将其转换为字符串)并用它创建了一个MemoryStream
对象。然后我将它传递给XDocument.Load
,这就像一个符咒。例如,假设xmlBytes
包含UTF8编码的XML,在它的开头有一个字节标记。然后,这就是解决问题的代码:
var stream = new MemoryStream(xmlBytes);
var document = XDocument.Load(stream);
就这么简单
如果以字符串开头,则仍然很容易(假设xml
是包含带字节顺序标记的xml的字符串):
我最近在.NET4升级方面遇到了一些问题,但在此之前,简单的答案是
String.Trim()
删除BOM表直到.net 3.5
然而,在.NET4中,您需要稍微更改它
String.Trim(new char[]{'\uFEFF'});
这也将去除字节顺序标记,尽管您可能还希望删除零宽度空间U+200B
String.Trim(new char[]{'\uFEFF','\u200B'});
您还可以使用此选项删除其他不需要的字符
一些进一步的信息来自
.NET Framework 3.5 SP1和早期版本维护此方法修剪的空白字符的内部列表。从.NET Framework 4开始,该方法修剪所有Unicode空白字符(即,在传递给Char.IsWhiteSpace方法时产生真实返回值的字符)。由于此更改,.NET Framework 3.5 SP1和早期版本中的修剪方法删除了两个字符:零宽度空格(U+200B)和零宽度不间断空格(U+FEFF)此外,.NET Framework 3.5 SP1和早期版本中的修剪方法不会修剪三个Unicode空白字符:蒙古语元音分隔符(U+180E)、窄不间断空格(U+202F)和中等数学空格(U+205F)
我在遇到这个问题后写了这篇文章
基本上,我没有使用BinaryReader类读取文件内容的原始字节,而是使用StreamReader类和一个特定的构造函数,该构造函数自动从我试图检索的文本数据中删除字节顺序标记字符。从字符串中直接删除该字符的快速简单方法:
private static string RemoveBom(string p)
{
string BOMMarkUtf8 = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
if (p.StartsWith(BOMMarkUtf8))
p = p.Remove(0, BOMMarkUtf8.Length);
return p.Replace("\0", "");
}
如何使用:
string yourCleanString=RemoveBom(yourBOMString);
当我有一个base-64编码的文件要转换成字符串时,我遇到了这个问题。虽然我可以将它保存到一个文件中,然后正确地读取它,但下面是我能想到的从文件的字节[]
到字符串的最佳解决方案(根据TrueWill的回答):
其中StartsWith(byte[])
是逻辑扩展名:
public static bool StartsWith(this byte[] thisArray, byte[] otherArray)
{
// Handle invalid/unexpected input
// (nulls, thisArray.Length < otherArray.Length, etc.)
for (int i = 0; i < otherArray.Length; ++i)
{
if (thisArray[i] != otherArray[i])
{
return false;
}
}
return true;
}
publicstaticboolstartswith(此字节[]thisrarray,字节[]otherArray)
{
//处理无效/意外的输入
//(null、thisArray.Length
当然,最好是在仍然处于字节数组级别时将其剥离,以避免不需要的子字符串/alloc。但是,如果您已经有一个字符串,这可能是处理此问题的最简单和最有效的方法
用法:
string feed = ""; // input
bool hadBOM = FixBOMIfNeeded(ref feed);
var xElem = XElement.Parse(feed); // now does not fail
//
///您可以通过以下方法获取或测试它:Encoding.UTF8.GetString(Encoding.UTF8.getPremission())[0];
///但是没有必要,这样我们就有了一个常量,因为这三个字节“[239187191]”(一个BOM)计算为一个C字符。
///
公共常数char BOMChar=(char)65279;
需要公共静态bool fixbomif(参考字符串str)
{
public static string GetUTF8String(byte[] data)
{
byte[] utf8Preamble = Encoding.UTF8.GetPreamble();
if (data.StartsWith(utf8Preamble))
{
return Encoding.UTF8.GetString(data, utf8Preamble.Length, data.Length - utf8Preamble.Length);
}
else
{
return Encoding.UTF8.GetString(data);
}
}
public static bool StartsWith(this byte[] thisArray, byte[] otherArray)
{
// Handle invalid/unexpected input
// (nulls, thisArray.Length < otherArray.Length, etc.)
for (int i = 0; i < otherArray.Length; ++i)
{
if (thisArray[i] != otherArray[i])
{
return false;
}
}
return true;
}
string feed = ""; // input
bool hadBOM = FixBOMIfNeeded(ref feed);
var xElem = XElement.Parse(feed); // now does not fail
/// <summary>
/// You can get this or test it originally with: Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble())[0];
/// But no need, this way we have a constant. As these three bytes `[239, 187, 191]` (a BOM) evaluate to a single C# char.
/// </summary>
public const char BOMChar = (char)65279;
public static bool FixBOMIfNeeded(ref string str)
{
if (string.IsNullOrEmpty(str))
return false;
bool hasBom = str[0] == BOMChar;
if (hasBom)
str = str.Substring(1);
return hasBom;
}
var preamble = Encoding.UTF8.GetPreamble();
if (!functionBytes.Take(preamble.Length).SequenceEqual(preamble))
preamble = Array.Empty<Byte>();
return Encoding.UTF8.GetString(functionBytes, preamble.Length, functionBytes.Length - preamble.Length);
using System.Xml.Linq;
void method()
{
byte[] bytes = GetXmlBytes();
XDocument doc;
using (var stream = new MemoryStream(docBytes))
{
doc = XDocument.Load(stream);
}
}
certficateThumbprint = Regex.Replace(certficateThumbprint, @"[^a-zA-Z0-9\-\s*]", "");