How can I remove accelerator characters from a str

2019-04-11 13:58发布

问题:

I have a caption for a GUI control, and I want to convert it to a simple text string. Specifically, I want to remove the accelerator metacharacters.

For example (examples assume WinForms):

  • Strip off single occurrences of the metacharacter: &Yes becomes Yes
  • Convert double occurrences to single: Income && Expense becomes Income & Expense

My code will know whether it's dealing with the Windows Forms syntax (where the accelerator metacharacter is &) or WPF (where it's _). However, this is in back-end code, so I don't want to take a dependency on any WinForms or WPF library functions -- I need to do this using the core (non-GUI) BCL assemblies. (And at that point, I figure that anything that works for WinForms would be trivial to modify for WPF.)

I can think of several ways to do this, but it's not clear which is simplest.

What's the simplest way to implement this "remove metacharacters if single, de-double if doubled"?

Update: I had assumed that WinForms and WPF both handled these basically the same, but it turns out they don't. WinForms will strip a lone metacharacter at the end of the string (Foo& becomes Foo), but WPF will not (Foo_ remains Foo_). Bonus points for an answer that addresses both.

回答1:

I've edited (removed) my previous answer. I think the simplest way would be this regular expression:

string input = "s&trings && stuf&f &";
input = Regex.Replace(input, "&(.)", "$1");

That correctly handles repeated ampersands as well as the case where the ampersand is the last character.

EDIT, based on additional provided information:

So the WinForms expression would be "&(.?)", and the WPF expression would be "_(.)". You ask for a solution that addresses both cases, but I'm not sure what you're asking. Your original question said that the code knows whether it's processing WPF format or WinForms format. So I would envision a method:

string StripAccelerators(string s, bool isWinForms)
{
    string pat = (isWinForms) ? "&(.?)" : "_(.)";
    return Regex.Replace(s, pat, "$1");
}

And, yes, I realize that using a Boolean flag in the interface is less than ideal. Ideally, you'd use an enumerated type, or perhaps have two separate methods.

I don't think you want to have a single regular expression that will perform both. It's possible, but then you'll end up removing underlines from WinForms strings, or ampersands from WPF strings.