Вы не можете сделать это в стандартном sed (1) , потому что там нет такой вещи, как \u
или \U
. Действительно, на всех моих системах (кроме одной) она выходит из строя - и молча, увы! Я попробовал версию sed
как на своем ноутбуке Mac, так и на рабочем столе Mac, а затем попробовал ее на нашем сервере Solaris и на нашем сервере OpenBSD. Я тоже попробовал это на одиночном AIX-боксе, и, конечно, он там не работал. (
Тем не менее, вы должны быть в состоянии сделать это переносным способом, который работает на тех системах, которые я тестировал:
% cat sample
VI.d5.5
VII.b2.1
VII.b2.2
VII.b2.3
VII.c1
% perl -wpe 's/([^.]+)\.(.)/$1.\u$2.$2/' /tmp/sample
VI.D.d5.5
VII.B.b2.1
VII.B.b2.2
VII.B.b2.3
VII.C.c1
Мало того, что он более портативный, он намного проще.
Это должно работать на любой версии Perl, выпущенной за последние 20 лет, включая perl4. Однако, если вы живете на переднем крае и у вас установлено не менее 5.10, вы можете сделать это следующим образом:
% perl -M5.10.0 -wpe 's/[^.]+\.\K(?=(.))/\u$1./' /tmp/sample
VI.D.d5.5
VII.B.b2.1
VII.B.b2.2
VII.B.b2.3
VII.C.c1
То, что ‑M5.10.0
просто для того, чтобы убедиться, что у вас действительно есть доступный и загруженный набор функций 5.10.
А как насчет Юникода?
Теперь предположим, что в ваших данных образца есть Unicode:
% cat /tmp/sample.utf8
Ⅵ.ð5.5
Ⅷ.ß2.3
Ⅺ.ç1
% uniquote /tmp/sample.utf8
\N{U+2165}.\N{U+F0}5.5
\N{U+2167}.\N{U+DF}2.3
\N{U+216A}.\N{U+E7}1
% uniquote -v /tmp/sample.utf8
\N{ROMAN NUMERAL SIX}.\N{LATIN SMALL LETTER ETH}5.5
\N{ROMAN NUMERAL EIGHT}.\N{LATIN SMALL LETTER SHARP S}2.3
\N{ROMAN NUMERAL ELEVEN}.\N{LATIN SMALL LETTER C WITH CEDILLA}1
Я могу гарантировать вам, что вы не найдете версию sed
, которая правильно работает с этими данными. Это испортит. Я подошел к нашему жертвенному Linux-боксу, и хотя ɢɴᴜsed
, который они там используют, работает с вашими примерами данных, он отказался от отображения одного из этих символов в моем более красивом наборе данных Unicode, даже когда у меня все настройки были настроены правильно. Но версия perl
все же сделала правильно.
Но с perl, просто добавьте параметры командной строки ‑CSD
, чтобы сообщить perl, что файлы данных и std {in, out, err} находятся в UTF ‑ 8, затем выполните те же команды, и вы увидите что-то, что действительно Qᴜɪᴛᴇ Iɴᴛᴇʀᴇsᴛɪɴɢ :
% perl -CSD -wpe 's/([^.]+)\.(.)/$1.\u$2.$2/' /tmp/sample.utf8
Ⅵ.Ð.ð5.5
Ⅷ.Ss.ß2.3
Ⅺ.Ç.ç1
% perl -CSD -wpe 's/[^.]+\.\K(?=(.))/\u$1./' /tmp/sample.utf8
Ⅵ.Ð.ð5.5
Ⅷ.Ss.ß2.3
Ⅺ.Ç.ç1
% perl -CSD -wpe 's/[^.]+\.\K(?=(.))/\U$1./' /tmp/sample.utf8
Ⅵ.Ð.ð5.5
Ⅷ.SS.ß2.3
Ⅺ.Ç.ç1
Как видите, есть разница между заголовком , который \u
делает и верхним регистром , который \U
делает. Это потому, что строчная буква «ß» - это «Ss» в заглавном, а «SS» в верхнем. Странно, но верно! По общему признанию, подобное происходит гораздо чаще с греческими буквами, чем с латинскими, как мы используем, но вы все равно хотите сделать это правильно.
Вот это all uniquote d, чтобы вы могли видеть, о каких именно кодах мы говорим:
% perl -CSD -wpe 's/[^.]+\.\K(?=(.))/\u$1./' /tmp/sample.utf8 | uniquote
\N{U+2165}.\N{U+D0}.\N{U+F0}5.5
\N{U+2167}.Ss.\N{U+DF}2.3
\N{U+216A}.\N{U+C7}.\N{U+E7}1
% perl -CSD -wpe 's/[^.]+\.\K(?=(.))/\u$1./' /tmp/sample.utf8 | uniquote -v
\N{ROMAN NUMERAL SIX}.\N{LATIN CAPITAL LETTER ETH}.\N{LATIN SMALL LETTER ETH}5.5
\N{ROMAN NUMERAL EIGHT}.Ss.\N{LATIN SMALL LETTER SHARP S}2.3
\N{ROMAN NUMERAL ELEVEN}.\N{LATIN CAPITAL LETTER C WITH CEDILLA}.\N{LATIN SMALL LETTER C WITH CEDILLA}1
Разве это не круто?