Вы можете использовать
<[^<>]*>|(?<!\p{L})(\p{L})(\p{L}*)
Регулярное выражение выполняет следующие действия:
<[^<>]*>
- соответствует <
, любые 0+ символов кроме <
и >
и затем >
|
- или (?<!\p{L})
- находит позицию, которой непосредственно не предшествует буква (\p{L})
- захватывает в группу1 любая буква (\p{L}*)
- вводит в группу 2 любые буквы 0+ (это необходимо, если вы хотите сделать остальную часть слова строчными.)
Затем проверьте,Группа 2 совпадает, и если да, используйте заглавную букву для первого значения группы и строчные буквы для второго, иначе верните все значение целиком:
var result = Regex.Replace(s, @"<[^<>]*>|(?<!\p{L})(\p{L})(\p{L}*)", m =>
m.Groups[1].Success ?
m.Groups[1].Value.ToUpper() + m.Groups[2].Value.ToLower() :
m.Value);
Если вам не нужно вводить строчные буквы в остальной части слова, удалитевторая группа и связанный с ней код:
var result = Regex.Replace(s, @"<[^<>]*>|(?<!\p{L})(\p{L})", m =>
m.Groups[1].Success ?
m.Groups[1].Value.ToUpper() : m.Value);
Чтобы заменить только первое вхождение, используя этот подход, необходимо установить флаг и обратить его вспять, как только будет найдено первое совпадение:
var s = "<style=foo>first non-tagged word 1st char upper</style>";
var found = false;
var result = Regex.Replace(s, @"<[^<>]*>|(?<!\p{L})(\p{L})", m => {
if (m.Groups[1].Success && !found) {
found = !found;
return m.Groups[1].Value.ToUpper();
} else {
return m.Value;
}
});
Console.WriteLine(result); // => <style=foo>First non-tagged word 1st char upper</style>
См. Демоверсию C # .