C# 有没有这样一种东西,比如;“用户定义的编码回退”;
当使用ASCII编码并将字符串编码为字节时,像C# 有没有这样一种东西,比如;“用户定义的编码回退”;,c#,encoding,ascii,fallback,C#,Encoding,Ascii,Fallback,当使用ASCII编码并将字符串编码为字节时,像ö这样的字符将产生? Encoding encoding = Encoding.GetEncoding("us-ascii"); // or Encoding encoding = Encoding.ASCI; data = encoding.GetBytes(s); 我正在寻找用不同的字符替换这些字符的方法,而不仅仅是问号。 示例: ä -> ae ö -> oe ü -> ue ß -> ss 如果不能将一个字
ö
这样的字符将产生?
Encoding encoding = Encoding.GetEncoding("us-ascii"); // or Encoding encoding = Encoding.ASCI;
data = encoding.GetBytes(s);
我正在寻找用不同的字符替换这些字符的方法,而不仅仅是问号。示例:
ä -> ae
ö -> oe
ü -> ue
ß -> ss
如果不能将一个字符替换为多个字符,我将接受是否可以将它们替换为一个字符(o
->o
)
现在有几种EncoderFallback
的实现,但我不明白它们是如何工作的。一个快速而肮脏的解决方案是在将字符串赋给
Encoding.GetBytes()
之前替换所有这些字符,但这似乎不是“正确”的方法。我希望我能给编码对象一个替换表 我怎样才能做到这一点 实现您想要的“最正确”的方法是实现一个定制的回退编码器,该编码器可以实现最佳的回退。由于各种原因,.NET中内置的一个在它将尝试最适合的字符方面是相当保守的(存在安全隐患,这取决于您计划使用什么来放置重新编码的字符串。)您的自定义回退策略可以根据您想要的任何规则进行最佳匹配 话虽如此,在您的回退类中,您最终将编写一个包含所有不可编码的Unicode代码点的巨型case语句,并手动将它们映射到最适合的备选方案。通过提前循环字符串并将不支持的字符替换为替换字符,可以实现相同的目标。回退策略的主要好处是性能:您只能在字符串中循环一次,而不是至少两次。除非你的关系很大,否则我不会太担心 如果您确实想要实现自定义的回退策略,您一定要阅读我的评论中的文章:。这并不难,但您必须了解编码回退是如何工作的 您提供了
Encoder.GetEncoding
方法作为自定义类的实现,该类必须派生自EncoderFallback
。不过,该类基本上只是实际工作的包装,这是在EncoderFallbackBuffer
中完成的。您需要缓冲区的原因是,回退不一定是一对一的过程;在您的示例中,您可能最终将一个Unicode字符映射为两个ASCII字符
当编码过程第一次遇到问题并需要依赖于您的策略时,它使用EncoderFallback
实现来创建EncoderFallbackBuffer
的实例。然后调用自定义缓冲区的Fallback
方法
在内部,缓冲区建立了一组要返回的字符,以代替不可编码的字符,并返回true
。从那里,编码器将重复调用GetNextChar
,只要剩余>0
和/或直到GetNextChar
返回CP 0,并将这些字符粘贴到编码结果中
这篇文章包含了一个实现,它非常准确地描述了您要做的事情;我已经复制了下面的基本框架,应该可以让您开始了
public class CustomMapper : EncoderFallback
{
// Use can override the "replacement character", so track what they
// give us.
public string DefaultString;
public CustomMapper() : this("*")
{
}
public CustomMapper(string defaultString)
{
this.DefaultString = defaultString;
}
public override EncoderFallbackBuffer CreateFallbackBuffer()
{
return new CustomMapperFallbackBuffer(this);
}
// This is the length of the largest possible replacement string we can
// return for a single Unicode code point.
public override int MaxCharCount
{
get { return 2; }
}
}
public class CustomMapperFallbackBuffer : EncoderFallbackBuffer
{
CustomMapper fb;
public CustomMapperFallbackBuffer(CustomMapper fallback)
{
// We can use the same custom buffer with different fallbacks, e.g.
// we might have different sets of replacement characters for different
// cases. This is just a reference to the parent in case we want it.
this.fb = fallback;
}
public override bool Fallback(char charUnknown, int index)
{
// Do the work of figuring out what sequence of characters should replace
// charUnknown. index is the position in the original string of this character,
// in case that's relevant.
// If we end up generating a sequence of replacement characters, return
// true, and the encoder will start calling GetNextChar. Otherwise return
// false.
// Alternatively, instead of returning false, you can simply extract
// DefaultString from this.fb and return that for failure cases.
}
public override bool Fallback(char charUnknownHigh, char charUnknownLow, int index)
{
// Same as above, except we have a UTF-16 surrogate pair. Same rules
// apply: if we can map this pair, return true, otherwise return false.
// Most likely, you're going to return false here for an ASCII-type
// encoding.
}
public override char GetNextChar()
{
// Return the next character in our internal buffer of replacement
// characters waiting to be put into the encoded byte stream. If
// we're all out of characters, return '\u0000'.
}
public override bool MovePrevious()
{
// Back up to the previous character we returned and get ready
// to return it again. If that's possible, return true; if that's
// not possible (e.g. we have no previous character) return false;
}
public override int Remaining
{
// Return the number of characters that we've got waiting
// for the encoder to read.
get { return count < 0 ? 0 : count; }
}
public override void Reset()
{
// Reset our internal state back to the initial one.
}
}
公共类CustomMapper:encoderCallback
{
//使用可以覆盖“替换字符”,以便跟踪它们的内容
//给我们。
公共字符串DefaultString;
公共CustomMapper():此(“*”)
{
}
公共CustomMapper(字符串defaultString)
{
this.DefaultString=DefaultString;
}
公共重写编码器FallBackBuffer CreateFallbackBuffer()
{
返回新的CustomMapperFallbackBuffer(此);
}
//这是我们可以替换的最大字符串的长度
//返回单个Unicode代码点。
公共覆盖整型MaxCharCount
{
获取{return 2;}
}
}
公共类CustomMapperFallbackBuffer:EncoderFallbackBuffer
{
CustomMapper fb;
公共CustomMapperFallbackBuffer(CustomMapper回退)
{
//我们可以将相同的自定义缓冲区用于不同的回退,例如。
//我们可能有不同的替换字符集用于不同的应用程序
//案例。这只是一个对父级的引用,以防我们需要它。
this.fb=回退;
}
公共覆盖布尔回退(char charUnknown,int索引)
{
//做一些工作,找出应该替换的字符序列
//charUnknown.index是此字符在原始字符串中的位置,
//以防万一。
//如果我们最终生成一系列替换字符,返回
//则编码器将开始调用GetNextChar。否则返回
//错。
//或者,不返回false,只需提取
//来自this.fb的DefaultString,并在失败情况下返回该字符串。
}
公共覆盖布尔回退(char charUnknownHigh、char charUnknownLow、int index)
{
//与上面相同,只是我们有一个UTF-16代理项对。规则相同
//应用:如果我们可以映射这对,则返回true,否则返回false。
//对于ASCII类型,很可能会在此处返回false
//编码。
}
public override char GetNextChar()
{
//返回替换的内部缓冲区中的下一个字符
//等待放入编码字节流的字符。如果
//我们都没有字符了,返回'\u0000'。
}
公共覆盖bool MovePrevious()
{
//回到我们返回的前一个角色并做好准备
//再次返回。如果可能,返回true;如果是
//不可能(例如,我们没有以前的字符)返回false;
}
公共覆盖剩余整数
{
//返回等待的字符数
//用于编码器读取。
获取{r