Мне нужно заставить diff
игнорировать регистр моих входных данных. Оба входа содержат немецкие умлауты, такие как ä и Ä. Опция -i
успешно заставляет diff
игнорировать регистр ввода для других символов, таких как a и A, но не для умляутов:
$ diff -i <(echo ä) <(echo Ä)
1c1
< ä
---
> Ä
Вывод должен быть пустым, поскольку ä и Ä должны восприниматься как одна и та же буква, если регистр игнорируется. Если я попробую это вместо этого:
$ diff -i <(echo a) <(echo A)
Тогда он работает как положено (нет вывода).
Я также попытался установить переменную среды LANG
, чтобы diff
использовал правильную локаль, но, похоже, это не оказало никакого влияния:
LANG=de_DE.UTF-8 diff -i <(echo ä) <(echo Ä)
Я пробовал разные значения LANG
.
Есть ли способ заставить diff
игнорировать немецкие умлауты?
(Я использую Ubuntu 22.04 FWIW.)
-i
не является стандартным вариантом сравнения - pubs.opengroup.org/onlinepubs/9699919799/utilities/diff.htmlGNU sed распознает их (echo äa:ÄA | sed 's/[[:lower:]]/\U&/g; s/[[:upper:]]/\L&/g'
); GNU tr нет (echo äa:ÄA | tr '[:lower:][:upper:]' '[:upper:][:lower:]'
)
@jhnc: Ну, у Gnu diff по крайней мере есть -i
, и поскольку ОП использует Ubuntu, мы можем догадаться, что он использует это.
@user1934428 user1934428 правда, я только что указал на это, поскольку «работает так, как ожидалось» в зависимости от реализации будет различаться.
Я не совсем специалист по Unicode, но, насколько я понимаю, это ошибка в diff
, и нормализация, предложенная JosefZ, должна выполняться самим diff
. Как насчет сообщить об этой проблеме как об ошибке?
Исправлены теги для этого вопроса.
@ user1934428, пожалуйста, посмотрите обновленный ответ…
Я думаю, что подход нормализации uconv
работает только для латинских символов (но этого достаточно для обработки умлаутов).
Следующий код должен позволять diff -i
работать со всеми символами верхнего или нижнего регистра UTF-8 (латиница, греческий, кириллица, адлам и т. д.):
case2ascii()(
perl -CSD -pe '
s/[[:lower:]]/c$&/g;
s/[[:upper:]]/C\l$&/g;
' "$@"
)
ascii2case()(
perl -CSD -pe '
s{([cC])(.)}{ $1 eq "c" ? $2 : uc($2) }ge;
' "$@"
)
diff -i <(echo äæðαа𞤱 | case2ascii) <(echo ÄÆÐΑА𞤏 | case2ascii) | ascii2case
c
в зависимости от ситуацииGNU sed также работает:
case2ascii()(
sed '
s/[[:lower:]]/c&/g;
s/[[:upper:]]/C\l&/g;
' "$@"
)
ascii2case()(
sed '
s/C\(.\)/\u\1/g;
s/c\(.\)/\1/g;
' "$@"
)
использование ascii
в названии не совсем правильно, поскольку вывод не полностью ASCII — это только та часть, которую, как мы ожидаем, diff попытается бесчувственно сравнить
Да, я мог бы записать весь ввод строчными буквами. Но тогда вывод также будет в нижнем регистре, поэтому исходный ввод больше не будет отображаться. Вместо этого я просто хочу игнорировать изменения регистра.
@Альфе ? вывод не в нижнем регистре — функция ascii2case
отменяет все изменения
Сравните нормализованные строки, см. Формы нормализации Юникода:
diff -i <(echo ä| uconv -x Any-NFD) <(echo Ä| uconv -x Any-NFD)
Примечание: использовано uconv
из sudo apt install icu-devtools
К вашему сведению:
Form String StrLen Unicode
---- ------ ------ -------
NFC äÄ 2 \u00e4\u00c4
NFD äÄ 4 \u0061\u0308\u0041\u0308
NFKC äÄ 2 \u00e4\u00c4
NFKD äÄ 4 \u0061\u0308\u0041\u0308
из info diff
[Emphasis mine]:
18.1.1 Обработка многобайтовых символов и символов различной ширины
«
diff
», «diff3
» и «sdiff
» рассматривают каждую строку ввода как строку. из однобайтовые символы. В некоторых случаях это может привести к неправильной обработке многобайтовых символов. Например, когда его просят игнорировать пробелы, «diff
» неправильно игнорировать многобайтовый символ пробела.Кроме того, «
diff
» в настоящее время предполагает, что каждый байт имеет ширину одного столбца, и это предположение неверно в некоторых локалях, например локалях, которые используйте кодировкуUTF-8
. Это вызывает проблемы с «-y
» или Вариант «--side-by-side
» из «diff
».Эти проблемы необходимо устранять, не оказывая при этом чрезмерного ущерба производительность утилит в однобайтовых средах.
Команда по интернационализации Технологического центра IBM GNU/Linux предложены патчи для поддержки интернационализированного «
diff
» (http://oss.software.ibm.com/developer/opensource/linux/patches/i18n/diffutils-2.7.2-i18n-0.1.patch.gz). К сожалению, эти патчи неполные и предназначены для более старых версий. версию «diff
», поэтому в этой области необходимо проделать дополнительную работу.
Ubuntu 24.04 LTS (GNU/Linux 5.15.153.1-microsoft-standard-WSL2 x86_64)
Я задавался вопросом о чем-то вроде этого или iconv. Кажется, в целом это не работает: например. æÆ
/ ðÐ
/ αΑ
/ аА
/ и т. д.
@jhnc ты прав; ответ дополнен цитатой из info diff
…
это не просто проблема различий GNU. busybox diff работает с кодом вопроса, но не может правильно обработать все символы. например: busybox diff -i <(echo äæðαа𞤱) <(echo ÄÆÐΑА𞤏)
(при условии, что это одна и та же строка в нижнем и верхнем регистре)
«Мне нужно, чтобы diff игнорировал регистр моих входных данных» — получайте удовольствие от кодирования, если инструмент еще этого не делает.