我遇到的具体问题是我必须用等效的Unicode下标替换化学式中的数字,因此H2SO4 => H 2 SO 4。 (这些下标不是字体调整,它们是特殊的unicode字符。)
所以我最初的剪辑是:
return unit.Replace("2", "₂").
Replace("3", "₃").
Replace("4", "₄").
Replace("5", "₅").
Replace("6", "₆").
Replace("7", "₇");
哪个有效,但显然不是特别有效。有关更优化算法的任何建议吗?
答案 0 :(得分:3)
只有10个可能的下标字符需要替换,大多数化学公式不会太长。出于这个原因,我认为您的实现效率并不是非常低效,我建议您在尝试优化代码之前对其进行基准测试。
但这是我尝试创建一个满足您需求的方法:
public string ToSubscriptFormula(string input)
{
var characters = input.ToCharArray();
for (var i = 0; i < characters.Length; i++)
{
switch (characters[i])
{
case '2':
characters[i] = '₂';
break;
case '3':
characters[i] = '₃';
break;
// case statements omitted
}
}
return new string(characters);
}
我建议避免使用StringBuilder
,除非你附加了大量的字符串,因为创建实例的开销实际上会降低你的代码效率。有关何时应该使用它的详细说明,请参见this post by Jon Skeet。
另外,鉴于案例陈述数量有限,我个人认为使用Dictionary<char,char>
不会增加任何可读性或性能优势,但在不同的情况下考虑使用它可能会有用。
但是如果你真的不得不对你的方法进行超级优化,你可以用以下代码替换case语句(感谢andrew建议):
public string ToSubscriptFormula(string input)
{
var characters = input.ToCharArray();
const int distance = '₀' - '0'; // distance of subscript from digit
for (var i = 0; i < characters.Length; i++)
{
if(char.IsDigit(characters[i]))
{
characters[i] = (char) (characters[i] + distance);
}
}
return new string(characters);
}
这里的诀窍是所有下标字符都是连续的,并且int
转换为char
会给你相应的字符。
最后,正如@nwellnhof在评论中建议的那样,char.IsDigit()
对于Unicode Nd Category中的一些非拉丁数字字符将返回true。
如果您的化学式包含此类字符,则应将该语句替换为c >= '0' && c<='9'
。这可能会比char.IsDigit
略快,但我不确定它是否会在大多数实际情况中产生影响。
答案 1 :(得分:2)
我很想做这样的事情:
public string replace(string input)
{
StringBuilder sb = new StringBuilder();
Dictionary<char, char> map = new Dictionary<char, char>();
map.Add('2', '₂');
map.Add('3', '₃');
map.Add('4', '₄');
map.Add('5', '₅');
map.Add('6', '₆');
map.Add('7', '₇');
char tmp;
foreach(char c in input)
{
if (map.TryGetValue(c, out tmp))
sb.Append(tmp);
else
sb.Append(c);
}
return sb.ToString();
}
为简单起见,Dictionary
在方法内部定义,但应在范围内的其他位置定义。
所以,很简单,只迭代input
字符串一次。对于每个字符,找到匹配的Dictionary条目(如果存在),并将该条目或原始字符附加到StringBuilder
,以避免创建多个字符串对象。
答案 2 :(得分:2)
我的第一个想法是关于平衡前缀数字的公式:
E.g。 2H 2(g)+ O 2(g)→2H 2 O(g)
据推测,你不希望这个取代领先的号码吗?
另外,我不确定上面提到为什么只需要8位数(甚至只有6位数)需要更换 - 不是所有数字都需要(0-9)?当然,你自己没有0和1,但你需要它们,例如10。
无论如何,尽管如上所述(我没有尝试实现,因为它不是问题),避免使用StringBuilder并对char数组进行操作似乎是有道理的,我宁愿避免使用大的switch语句。 / p>
public class Program
{
public static void Main()
{
Console.WriteLine(SubscriptNums("C6H12O6"));
}
public static string SubscriptNums(string input)
{
char[] replacementChars = { '₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉' };
int zeroCharIndex = (int)'0';
char[] inputCharArray = input.ToCharArray();
for(int i = 0; i < inputCharArray.Length; i++)
{
if (inputCharArray[i] >= '0' && inputCharArray[i] <= '9')
{
inputCharArray[i] = replacementChars[(int)inputCharArray[i] - zeroCharIndex];
}
}
return new string(inputCharArray);
}
}
编辑1 - 删除数字值为“0”的幻数。
编辑2 - 删除了对IsDigit的使用。
答案 3 :(得分:0)
您可以迭代字符串并检查每个字符。如果要替换,请将相应的字符附加到StringBuilder。如果没有,只需添加原始字符。这样,您只需迭代字符串一次,而不是每次替换一次。此外,由于字符串是不可变的,每次调用String.Replace()
都会为结果创建一个新的字符串副本,该副本将立即再次进行GC。
StringBuilder sb = new StringBuilder();
for (int i = 0; i < unit.Length; i++) {
switch(unit[i]) {
case '2': sb.Append('₂'); break;
case '3': sb.Append('₃'); break;
...
default: sb.Append(unit[i]); break;
}
}
output = sb.ToString();
你也可以介绍一些替代字典,比如Abdullah Nehir建议
StringBuilder sb = new StringBuilder();
Dictionary<char, char> replacements = new Dictionary<char, char>();
//put in the pairs
for (int i = 0; i < unit.Length; i++) {
if (replacements.ContainsKey(unit[i]))
sb.Append(replacement[unit[i]];
else
sb.Append(unit[i]);
}
您可以使用foreach循环
迭代字符串,而不是通过索引访问值foreach (char c in unit) {
if (replacements.ContainsKey(c))
sb.Append(replacements[c]);
else
sb.Append(c);
}
答案 4 :(得分:0)
如果您正在寻找一些优雅的代码,而不必为每个字符键入string.Replace
,那么这将对您有所帮助:
public static string Replace(string input)
{
char[] inputCharArr = input.ToCharArray();
StringBuilder sb = new StringBuilder();
foreach (var c in inputCharArr)
{
int intC = (int)c;
//If the digit was a number ([0-9] are [48-57] in unicode),
//replace the old char with the new char
//(8272 when added to the unicode of [0-9] gives the desired result)
if (intC > 47 && intC < 58)
sb.Append((char)(intC + 8272));
else sb.Append(c);
}
return sb.ToString();
}
如果您想知道评论的内容,请参阅编辑历史记录。