LINUX.ORG.RU

В Си предложили добавить switch-case для строк

 , ,


0

4

Привет, чат!

Спустя много лет, в язык Си наконец предложено добавить возможность использовать выражение switch-case для строк. Например, можно будет писать вот такое:

const char *s = get_some_string();

switch(s) {
case "this":
  handle_this();
  break;
case "that":
  handle_that();
  break;
default:
  handle_other();
  break;
}

Таким образом, в Си будет чуть меньше способов отстрелить себе ноги.

Ссылка на предложение: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3895.pdf



Последнее исправление: hobbit (всего исправлений: 1)
Ответ на: комментарий от VIT

ну ... мы пошли другим путем и ... пришли к тому-же!
зю: знал-бы я что это hateyoufeel - прошел-бы мимо :о)

sunjob ★★★★★
()
Последнее исправление: sunjob (всего исправлений: 1)
Ответ на: комментарий от shdown

Неа, не понимаешь, у меня нет основного языка, и вообще эмоционально не привязываюсь к каким-то там язычкам(и наоборот тоже). И что это за проекции такие, я же вот не делаю таких снисходительных намёков - «а ну понятно, типичный сишник, т.е. полуграмотное, необучаемое хамло с дико раздутым «хакирным» самомнением» - хотя оснований у меня для этого, глядя на лор, гораздо больше.

(существование невыровненных указателей) неопределённое поведение вообще-то.

Существовать как раз могут, писать/читать через них как обычно нельзя, но через memcpy можно. Это специальный интринсик с ослаблением убшных правил. Долгое время это чуть ли не единственное переносимое стандартное средство было для подобных операций(и обхода стрикт алиасинга). Похоже на ложно-положительное, можно как-то так уговорить - https://godbolt.org/z/a4Gss16z4, чтобы не ругалось. Тут https://godbolt.org/z/E85oeE9er видно что для данной архитектуры правильно побайтово разбирать, и компилятор перевёл memcpy как надо.

zurg ★★
()
Ответ на: комментарий от zurg

Похоже на ложно-положительное

Существовать как раз могут

Понятно.

https://www.dii.uchile.cl/~daespino/files/Iso_C_1999_definition.pdf, 6.3.2.3 Pointers:

7 A pointer to an object or incomplete type may be converted to a pointer to a different object or incomplete type. If the resulting pointer is not correctly aligned57) for the pointed-to type, the behavior is undefined.

shdown ★★
()
Ответ на: комментарий от zurg

Это специальный интринсик с ослаблением убшных правил.

  1. memcpy не обязан быть интринсиком. В твоём же примере можно прямо задействовать memcpy через -fno-builtin-memcpy.
  2. Тут нет ослабления UB-шных правил, потому что UB никакого нет. memcpy принимает на вход указатели на void. Любой указатель на вход преобразуется в указатель на void, к которому нет требований по выравниванию.

Ты правильно написал, что

Более общее и стандартное во всех смыслах - https://godbolt.org/z/7a191vhnM . Не завязано вообще ни на что, и работать будет на любом железе.

r--r--r--
()
Ответ на: комментарий от shdown

Оппа, с одной стороны даже соглашусь, но с другой - сишный стандарт специфичная мутная писанина с кучей исключений. И санитайзер таки замолчал. Давай более корректно оформим - https://godbolt.org/z/zj8YW17nP, но идея правильная и это лучше чем gcc специфичный аттрибут. Но вот же проклятый язычок - за счёт похеривания типобезопасности, и теперь то ли надо отдельным аргументом размер таскать, то ли через имя функции напоминать что это для конкретного типа. И раз уж ты вспомнил раст, в нём указатели (в отличие от ссылок) могут быть невыровненными (почему видать меня и переклинило), так что вот он более системный язык, с чем и поздравляю.

zurg ★★
()
Ответ на: комментарий от zurg

нём указатели (в отличие от ссылок) могут быть невыровненными

Да, но нет. Невыровненный указатель может быть невалидным указателем. Чтобы быть валидным он должен быть корректно выровнен.

так что вот он более системный язык, с чем и поздравляю.

Вообще никакой разницы в этом месте с си. На практике под большинство платформ ты можешь поместить не выровненный адрес в переменную-указатель, и получишь ошибку выполнения там же, где и в расте - на доступе.

r--r--r--
()
Ответ на: комментарий от seiken

В Си нет строк, там только массивы байт. Остальное, сахар.

Vic
()

Вангую, следующей идеей будет вставлять в case регекс. И да, о локализации и ширине строк никто не подумал. И что будет в случае:

switch(s) {
case "this":
  handle_this();
  break;
case L"this":
  handle_long_this();
  break;
default:
  handle_other();
  break;
}
gns ★★★★★
()
Ответ на: комментарий от gns

Через 9 лет введут новый синтаксис для switch над L"", только со старыми ключевыми словами. Что-то типа

switch long (s) {

shdown ★★
()
Ответ на: комментарий от gns

И да, о локализации и ширине строк никто не подумал

Как и в Си в целом. Живого кода с wchar_t я ни разу в жизни не видел, для обработки юникода обычно тащат libicu.

yorshka
() автор топика
Ответ на: комментарий от yorshka

Я это написал для демонстрации дебилизма предложения. По моему, фича крайне вредная и не реализуемая в общем случае.

Живого кода с wchar_t я ни разу в жизни не видел, для обработки юникода обычно тащат libicu.

Это ты легаси-кода, который компилится на виндах и линухе, возможно мало видел :( И libicu тащат не всегда. Какой в пень libicu? Libicu тащит буст по зависимостям, но это плюсы.

gns ★★★★★
()
Ответ на: комментарий от dataman

Ну, как бы, от сборки зависит. Сейчас что-то в бусте 1.83 я прямых зависимостей не нашел, но было время, когда я замечал, что при установке libboost-all-dev libicu тащится по зависимостям. А, ну и вот. Вуаля:

gleb@develop-3:~/$ apt-cache rdepends libicu-dev
libicu-dev
Reverse Depends:
....
  libboost-regex1.83-dev
  libboost-regex1.74-dev
...

Искал в локалях, а нашел в регексе :)

gns ★★★★★
()
Последнее исправление: gns (всего исправлений: 1)
Ответ на: комментарий от gns

Для char*-строк есть strcmp. Для wchar_t*-строк есть wcscmp. А как должно работать сравнение строк разных типов? Для этого, вроде бы, и функции нет.

shdown ★★
()
Ответ на: комментарий от yorshka

Хм…

set -e

true > uses_wchar.txt

test_if_uses_wchar() {
    local pid
    {
        exec "$@" < /dev/tty
    } & pid=$!
    sleep 3
    if grep -q /usr/lib/locale/locale-archive /proc/$pid/maps; then
        echo "$1 YES" >> uses_wchar.txt
    else
        echo "$1 NO" >> uses_wchar.txt
    fi
    if kill $pid; then
        wait $pid || true
    fi
    reset || true
}

test_if_uses_wchar python3
test_if_uses_wchar perl
test_if_uses_wchar php
test_if_uses_wchar node
test_if_uses_wchar ruby
test_if_uses_wchar lua5.5

test_if_uses_wchar /usr/lib/ghc/bin/ghc --interactive

test_if_uses_wchar color-picker
test_if_uses_wchar firefox

test_if_uses_wchar mc

test_if_uses_wchar gcc -x c /dev/stdin
test_if_uses_wchar clang -x c /dev/stdin
Результат:
python3 YES
perl YES
php YES
node NO
ruby YES
lua5.5 YES
/usr/lib/ghc/bin/ghc YES
color-picker YES
firefox YES
mc YES
gcc YES
clang NO

shdown ★★
()
Ответ на: комментарий от shdown

П.С. да и вообще все программы, которым нужно взаимодействовать с терминалом нетривиальным образом, используют wchar_t, потому что wcwidth() есть только для него.

shdown ★★
()
Ответ на: комментарий от gns

Каком зоопарке и почему компилятор должен в нём «разбираться»? Это ты предложил добавить поддержку ещё и wchar_t-строк. И ещё каким-то образом мешать в одном и том же switch char* и wchar_t*, про ожидаемую тобой семантику чего я у тебя и спросил (ответа не последовало).

shdown ★★
()
Ответ на: комментарий от shdown

Каком зоопарке и почему компилятор должен в нём «разбираться»?

Ну вот ровно в разборе свича со строками разных типов. Да и одного типа: кстати. Компилятору что, конечный автомат генерить на такой свич?

Я как раз считаю, что это вредно И в общем случае не реализуемо. Ты внимательно читай весь мой спич. Я просто указал на проблему и предположил, куда может привести добавление подобной фичи. А потом люди захотят в case-блок регекс засунуть ала тот же шелл... :(

Я как раз и указал, что семантика подобного свича не понятна изначально. Или мы ограничиваем case-блоки строками одного типа и кодировки? И где определяется, что нельзя мешать широкие и узкие строки в одном свиче?

А если так:

switch(s) {
case "السّلام عليكم":
 say("Алейкум салам!"):
  break;
case "שָׁלוֹם":
  say("И вам Шалом"!);
  break;
case "你好":
  say("Ни хао!");
case "Здравствуйте!":
  say("И Вам не хворать!"):
default:
  say("Чо?")
  break;
}

И сколько тут байт на символ в каждой строке? Типа UTF-8 by default или как?

gns ★★★★★
()
Ответ на: комментарий от gns

Понятно. Иди кури, как это всё на низком уровне устроено. А то ерунду какую-то пишешь, только позоришься.

shdown ★★
()
Ответ на: комментарий от shdown

Я почти уверен, что glibc её где-то подсасывает. Хотя в коде GHC wchar_t и правда встречается пару раз, тут спорить не буду.

yorshka
() автор топика
Ответ на: комментарий от yorshka

Он её подсасывает, но динамически, когда начинаешь функции использовать. По-твоему, шланг или nodejs не используют libc?

И это, как без <wchar.h> понять, сколько знакомест в терминале займёт такая-то строка, если её тупо вывести (пусть даже исходя из того, что локаль — *.UTF-8)?

shdown ★★
()
Ответ на: комментарий от shdown

Он её подсасывает, но динамически, когда начинаешь функции использовать. По-твоему, шланг или nodejs не используют libc?

Я бы не удивился, если бы это было так в случае с нодой. Если мне не изменяет память, разрабы голанга вполне пытались избавиться от зависимости от libc.

И это, как без <wchar.h> понять, сколько знакомест в терминале займёт такая-то строка, если её тупо вывести (пусть даже исходя из того, что локаль — *.UTF-8)?

Через libicu сотоварищи, конечно же. Потому что версия юникода в libc вполне может быть старше говна мамонта и не поддерживать самые свежие эмоджи или Z̶̡̧̟̼̮̺̙̮̻͈̐A̸̧̧̛̦̱͇̟̻̙̯̗̓̍̽̈́̂̌͗̏̈͂͆͒͋̉̏͋͐́̚̕̕͝͠͠L̷̨̢̨̛̰̘̤̗͍̄̅̊͌̎̃͛͛͊̆̊̐͑̊̽͐̉͋̋͆̇̇͋̈̾̆̕͝G̵̡̨͈̣̪̲͙̖̰̤̯̭̗̥̊̓͛̉͂̐̍͂͌̽͊̔̃͒̈̈̾͆͗͑O̴̡̢̧̡͎̤̞̹̼͎̠̲͈̞̱͇̗͕͇̠͎͈̰̦͒̊̎͜ͅ ̸̧̱͈̟̬̳̦̯͕͍͔̲͙̻͈̤̹̼̟͇͖̮̮͖̼̯͓̩͔̮̳̲̏̃̎̓̾͘͠T̷̰̜͈̟̰͋̈́͐͂̇͌̎̚͝Ḙ̵̢̢̛͕͎̜͓͓̫̦̮̘̞̭̜͇̟͚̙͋̅̈́́̓͊̾͒̿̌͋̊͋̈̋̿̈̒̒̇͒͛̏̚̚̕̕X̵̨̢̢̛̭͚̯͕̤̖͉̦̗̫̹̺̱̼̣̍̐͌̇̌́͆̃̍͑̓̃T̶̡̧̧̻̻̫͖̯̲͕͙̞͕̲͇͈̘̻͙͚̱̩͇̘͔̭̟͎̈́̃̈̀̃̇͌̐͛͜ͅͅ.

yorshka
() автор топика
Ответ на: комментарий от shdown

Тебе в Boundary Analysis и Text Shaping. Судя по всему, шейпер из ICU убрали и теперь рекомендуют использовать HarfBuzz, поэтому ссылка на него.

Вообще, подсчёт места на экране под юникодный текст – это лютая залупа. Ради интереса, погугли «black dot of death iphone», чтобы оценить масштабы ада.

yorshka
() автор топика
Ответ на: комментарий от yorshka

Да не место в пикселях на экране, а количество знакомест в терминале (на сколько столбцов сдвинется курсор в терминале, если в этот терминал эту строку вывести через write()).

Ты вообще читаешь, на что отвечаешь?

shdown ★★
()
Ответ на: комментарий от shdown

Да не место в пикселях на экране, а количество знакомест в терминале (на сколько столбцов сдвинется курсор в терминале, если в этот терминал эту строку вывести через write()).

А это примерно одно и то же здесь лол. Юникод – он такой, да. Попробуй сам с помощью wchar_t и сишной магии посчитать, сколько знакомест в терминале займёт «в̶̨̩̖̥̠̻̣̟͙̋̒̄̍̋̊̄̂̌͐́͛̊̒̈́̉̈́̆̽̾̿͗̈́̆̅̅͐̓̐͊̄͋̿͐̾̈̔̅̾̍̆͋͒̀̿̑̓͆̀̎̔̔̀̔̕͘̕͝͝͠о̷̞̲̲͓̖̭͕̫͓͈̼̜̟̖̖̪͇̠̪͍̻̹͚̗̻̦͕͇͊́̐̉̀̉͗̔͛̊̔͊́͂͑̄͐̈́̓̐̈́̂̏̾͘͝͝т̴̨̧̨̨̦͓̦̟̻͇̘̙͇̖͎͇̥̱̘̫͚̳̙̫̣͓͖̠̼̥̲̗͕̦̊͗͂͐̉̎̃̆̃̒̄̽̋̂͒̍́͒͋̔̋̉̌́̒̏̽̾̈́̽̐͑́̅͗̓̍͂̐̇̾̈́̍̅͂̕͘̚͝͝ ̴̡̡̨̧̘͚͎̭̗̜̭̮̘̫̮͎̰̤̝̝̩͇̤̪̯̱̪̹͉̥̹̘̱͚̖̝͈̟̫͓̻̫̍͌́͊̀͑͒̃̒̋̈́͒͆̓͑̀̋̏͐̽̐̑͊̽͊̐̎̒̈́͗̌̋̉͆͒́̒̍̓̔̿͂͌͐̽̀̀̉̅͊̋̋̀̃̆̚̚͘̕͠т̵̡̢̡̡̧̡̱̖̙̹̝̦̮̲͖̹̩͎̥̼̰̰̟̜̠͔̲̗͖̖͚̼̫͔͓͈̲̩̖̻̙͚̙̰̝̳̥͇̮̳̰͈̮̣̏̓̏̈́͋̋̚͘͜͜͝ͅа̵̡̨͓̯͙͇͚̘̬̲̣̮̬͔͚̠̹̼͚̮̩̥̘̼̝̖͒͗̆̒̅̈̀̂̃̽̿̎̓̐͘͜͝ͅк̷͔̏̀̀̓͗͑̈́͂̆̊̃͛̅͌̿̈̎̄̀̌̈̀́̃̔̍́̾̈́͊̚͠͠͝о̵̧̡̧̧̧̧̡̱̳͕̝̫̝̱͈͕͙̦̫̞̱͓̺̻̘̘͉̦͍͎̥̝͇͖͙̖͖̰̺͍̤̘͙̰́̂͊̕͜͜͝ͅй̸̧͇͔̳̘̬̗̼͔͉͉̮̪̰̳̹̦̟͚̞̔̓́̽̽̔͋̆̓̍̃̎̈́̀̂̈̆͗̿̍̈́̉̃͛̽̾̑̀ ̴̡̧̡̡̛͙̲̜͇̌̒̿̀́̉͋͂͑̓̋̇̚͜ͅт̶̛̭̎͊̑̿͛̏͆̀̿̓̌̌͋͋̍̂́̌̓̅̈̓̔̌͘̕͝е̷̡̛̛̜̰͚̜̱̮̂̄̓̈̒̔̔͊̂̐̀̈́̓̃̒̋͑̀̈̀̃̿̒͌̀͋̂̾̈́̔̒͒͂̓̑͑̀̾́́̍̆̐̿̔̓̌̆͂̽̀̕͘͘̕͘̚̚͠͝͝к̷̧̡̡̨̧̛̛̛̗̭̲̭̜͍̙̖̩̮̟̻͇̞̮͉͓̱͔̩̣̪̮͎̩̠̜͓̗̎̐̏̐̈́̀̈́̉͛͌̾̌̋̅͌̍͛̒͒͊̈́̈́͗̏̅͛̀̌́̏͆̎̄̾̊͋́͂̓͛͜͝͠͝ͅс̷̡̢̡̧̨̙͕̱̼͎̞̪͖͍̯̰͖̖̬̟͔̫̳̋̄͗̓̒̊̈́̓̍́̽͊̄̈́̓̈́̀т̸̡̨̡̧̨̮͙̫͎̳̲͎͓͚̣͙̞̠̻͉̟͉̟̯͔̣̭̭̩̝̼͎͍̠̥̣̺̠͖͍̪͎̇͜͜͜ͅͅ».

Ты вообще читаешь, на что отвечаешь?

Ага. Это ты не очень понимаешь, что именно ты спрашиваешь.

yorshka
() автор топика
Ответ на: комментарий от shdown

Цитирую:

Encoding: A string switch inherits the existing C translation from source to the execution character set unchanged. It introduces no new character set conversions, locale-dependent matching, or Unicode normalization passes. The following two constructs are semantically identical with respect to encoding:

Так вот, если все рассматривается как поток байт, то весь этот юникод идет лесом. В моем примере арабица и евреица с BIDI-байтом и без него визуально неотличимы. И да, в документе ничего не сказано о том, каким способом они предлагают реализовать эффективный парсер со сложностью O(k) вместо O(n*k), которую имеет цепочка условных операторов и strcmp. Опять же, рассуждения на тему constrain violation при различии типов переменной в операторе switch и строк в case-блоках лично меня вгоняет в когнитивный диссонанс, если не сказть в ужас. Какие в пень констрейнты в Си? У авторов какая-то каша в голове.

Так что иди сам внимательо предложенный текст почитай раза три. Может сам поймешь убожество предложенного. И да, почитай драгонбук, а именно ту главу, в которой идет речь о конструировании конечных автоматов для разбора регексов.

Эффективный парсер со сложностью O(k) - это та же задача. Строки в case-блоках преобразуются в регекс и количество конечных состояний автомата соответствует количеству строк. Если сматчена одна из альтернатив, то вызывается функция из case-блока. И да, исходник начинает зависеть от кодировки строковых литералов. Упаси ТНБ его из UTF в КОИ-8 конвертнуть :) В общем иди сам кури матчасть, может поймешь всю глубину проблем, которые возникнут при реализации этого предложения.

gns ★★★★★
()
Последнее исправление: gns (всего исправлений: 1)
Ответ на: комментарий от yorshka

Попробуй сам с помощью wchar_t и сишной магии посчитать, сколько знакомест в терминале займёт «в̶̨̩̖̥̠̻̣̟͙̋̒̄̍̋̊̄̂̌͐́͛̊̒̈́̉̈́̆̽̾̿͗̈́̆̅̅͐̓̐͊̄͋̿͐̾̈̔̅̾̍̆͋͒̀̿̑̓͆̀̎̔̔̀̔̕͘̕͝͝͠о̷̞̲̲͓̖̭͕̫͓͈̼̜̟̖̖̪͇̠̪͍̻̹͚̗̻̦͕͇͊́̐̉̀̉͗̔͛̊̔͊́͂͑̄͐̈́̓̐̈́̂̏̾͘͝͝т̴̨̧̨̨̦͓̦̟̻͇̘̙͇̖͎͇̥̱̘̫͚̳̙̫̣͓͖̠̼̥̲̗͕̦̊͗͂͐̉̎̃̆̃̒̄̽̋̂͒̍́͒͋̔̋̉̌́̒̏̽̾̈́̽̐͑́̅͗̓̍͂̐̇̾̈́̍̅͂̕͘̚͝͝ ̴̡̡̨̧̘͚͎̭̗̜̭̮̘̫̮͎̰̤̝̝̩͇̤̪̯̱̪̹͉̥̹̘̱͚̖̝͈̟̫͓̻̫̍͌́͊̀͑͒̃̒̋̈́͒͆̓͑̀̋̏͐̽̐̑͊̽͊̐̎̒̈́͗̌̋̉͆͒́̒̍̓̔̿͂͌͐̽̀̀̉̅͊̋̋̀̃̆̚̚͘̕͠т̵̡̢̡̡̧̡̱̖̙̹̝̦̮̲͖̹̩͎̥̼̰̰̟̜̠͔̲̗͖̖͚̼̫͔͓͈̲̩̖̻̙͚̙̰̝̳̥͇̮̳̰͈̮̣̏̓̏̈́͋̋̚͘͜͜͝ͅа̵̡̨͓̯͙͇͚̘̬̲̣̮̬͔͚̠̹̼͚̮̩̥̘̼̝̖͒͗̆̒̅̈̀̂̃̽̿̎̓̐͘͜͝ͅк̷͔̏̀̀̓͗͑̈́͂̆̊̃͛̅͌̿̈̎̄̀̌̈̀́̃̔̍́̾̈́͊̚͠͠͝о̵̧̡̧̧̧̧̡̱̳͕̝̫̝̱͈͕͙̦̫̞̱͓̺̻̘̘͉̦͍͎̥̝͇͖͙̖͖̰̺͍̤̘͙̰́̂͊̕͜͜͝ͅй̸̧͇͔̳̘̬̗̼͔͉͉̮̪̰̳̹̦̟͚̞̔̓́̽̽̔͋̆̓̍̃̎̈́̀̂̈̆͗̿̍̈́̉̃͛̽̾̑̀ ̴̡̧̡̡̛͙̲̜͇̌̒̿̀́̉͋͂͑̓̋̇̚͜ͅт̶̛̭̎͊̑̿͛̏͆̀̿̓̌̌͋͋̍̂́̌̓̅̈̓̔̌͘̕͝е̷̡̛̛̜̰͚̜̱̮̂̄̓̈̒̔̔͊̂̐̀̈́̓̃̒̋͑̀̈̀̃̿̒͌̀͋̂̾̈́̔̒͒͂̓̑͑̀̾́́̍̆̐̿̔̓̌̆͂̽̀̕͘͘̕͘̚̚͠͝͝к̷̧̡̡̨̧̛̛̛̗̭̲̭̜͍̙̖̩̮̟̻͇̞̮͉͓̱͔̩̣̪̮͎̩̠̜͓̗̎̐̏̐̈́̀̈́̉͛͌̾̌̋̅͌̍͛̒͒͊̈́̈́͗̏̅͛̀̌́̏͆̎̄̾̊͋́͂̓͛͜͝͠͝ͅс̷̡̢̡̧̨̙͕̱̼͎̞̪͖͍̯̰͖̖̬̟͔̫̳̋̄͗̓̒̊̈́̓̍́̽͊̄̈́̓̈́̀т̸̡̨̡̧̨̮͙̫͎̳̲͎͓͚̣͙̞̠̻͉̟͉̟̯͔̣̭̭̩̝̼͎͍̠̥̣̺̠͖͍̪͎̇͜͜͜ͅͅ».

Да легко.

$ cat otakoi.txt; md5sum otakoi.txt # с переводом строки; MD5 для воспроизводимости
о̷̞̲͓̖̭͕̫͈̼̜̟̪͇̠͍̻̹͚̗̦͊́̐̉̀͗̔͛̊͂͑̄͐̈́̓̂̏̾͘͝т̴̨̧̦͓̟̻͇̘̙̖͎̥̱̫͚̳̣͖̠̼̲̗͕̊͗͂͐̉̎̃̆̒̄̽̋̂͒̍́͋̔̌̏̾̈́̐͑́̅̓̇̕͘̚͝ ̴̡̨̧̘͚͎̭̗̜̮̫̰̤̝̩͇̪̯̱̹͉̥̖͈̟͓̻̍͌́͊̀͑͒̃̒̋̈́͆̓̀̏͐̽̐̑̎͗̌̉̔̿͂̅̆̚͘̕͠т̵̡̢̧̱̖̙̹̝̦̮̲͖̩͎̥̼̰̟̜̠͔̗͚̫͓͈̻̳͇̣̏̓̈́͋̋̚͘͜͝ͅа̵̡̨͓̯͙͇͚̘̬̲̣̮͔̠̹̼̩̥̝̖͒͗̆̒̅̈̀̂̃̽̿̎̓̐͘͜͝ͅк̷͔̏̀̓͗͑̈́͂̆̊̃͛̅͌̿̈̎̄̌̀́̔̍́̾͊̚͠͝о̵̧̡̱̳͕̝̫͈͙̦̞͓̺̻̘͉͍͎̥͇͖̖̰̤́̂͊̕͜͝ͅй̸̧͇͔̳̘̬̗̼͉̮̪̰̹̦̟͚̞̔̓́̽͋̆̓̍̃̎̈́̀̂̈͗̿̉͛̾̑̀ ̴̡̧̛͙̲̜͇̌̒̿̀́̉͋͂͑̓̋̇̚͜ͅт̶̛̭̎͊̑̿͛̏͆̀̓̌͋̍̂́̓̅̈̔͘̕͝е̷̡̛̜̰͚̱̮̂̄̓̈̒̔͊̐̀̈́̓̃̋͑̿͌͋̾͒͂̑̀́̍̆̌̽̕͘̚͠͝к̷̧̡̨̛̗̭̲̜͍̙̖̩̮̟̻͇̞͉͓̱͔̣̪͎̠̎̐̏̈́̀̉͛͌̾̌̋̅̍̒͒͊͗̀́͆̄̊͋͂̓͜͝͠ͅс̷̡̢̧̨̙͕̱̼͎̞̪͖͍̯̰̖̬̟͔̫̳̋̄͗̓̒̊̈́̓̍́̽͊̀т̸̡̨̧̮͙̫͎̳̲͓͚̣̞̠̻͉̟̯͔̭̩̝̼͍̥̺͖̪̇͜ͅ
f3cd194b468ac9c372c55c5d9b8560b9  otakoi.txt
$ cat foo.c
#define _XOPEN_SOURCE
#include <wchar.h>
#include <stdio.h>
#include <locale.h>

int main()
{
    if (!setlocale(LC_ALL, "")) {
        fprintf(stderr, "setlocale() failed.\n");
        return 1;
    }

    wchar_t buf[1024];
    if (!fgetws(buf, 1024, stdin)) {
        fprintf(stderr, "fgetws() failed.\n");
        return 1;
    }

    size_t len = wcslen(buf);
    while (len && (buf[len - 1] == L'\n' || buf[len - 1] == L'\r')) {
        --len;
    }

    int w = wcswidth(buf, len);
    printf("%d\n", w);

    return 0;
}
$ tcc -run foo.c < otakoi.txt
14
$ cat test_otakoi.bash
get_cursor_column() {
    echo -e '\033[6n' >&2
    local res
    IFS= read -rd R res || return $?
    res=${res#*'['}
    res=${res#*;}
    echo "$res"
}

# Каждый раз переводим строку с помощью echo без аргументов, потому что
# get_cursor_column в процессе работы передвигает курсор вправо.

# Замеряем позицию курсора в самом левом столбце (должно быть 1).
echo
pos1=$(get_cursor_column)

# Замеряем позицию курсора после вывода текста (но без '\n').
echo
echo -n "$(cat otakoi.txt)"
pos2=$(get_cursor_column)

echo
echo "pos1=$pos1, pos2=$pos2, delta=$(( pos2 - pos1 ))"
$ bash test_otakoi.bash


^[[27;1R
о̷̞̲͓̖̭͕̫͈̼̜̟̪͇̠͍̻̹͚̗̦͊́̐̉̀͗̔͛̊͂͑̄͐̈́̓̂̏̾͘͝т̴̨̧̦͓̟̻͇̘̙̖͎̥̱̫͚̳̣͖̠̼̲̗͕̊͗͂͐̉̎̃̆̒̄̽̋̂͒̍́͋̔̌̏̾̈́̐͑́̅̓̇̕͘̚͝ ̴̡̨̧̘͚͎̭̗̜̮̫̰̤̝̩͇̪̯̱̹͉̥̖͈̟͓̻̍͌́͊̀͑͒̃̒̋̈́͆̓̀̏͐̽̐̑̎͗̌̉̔̿͂̅̆̚͘̕͠т̵̡̢̧̱̖̙̹̝̦̮̲͖̩͎̥̼̰̟̜̠͔̗͚̫͓͈̻̳͇̣̏̓̈́͋̋̚͘͜͝ͅа̵̡̨͓̯͙͇͚̘̬̲̣̮͔̠̹̼̩̥̝̖͒͗̆̒̅̈̀̂̃̽̿̎̓̐͘͜͝ͅк̷͔̏̀̓͗͑̈́͂̆̊̃͛̅͌̿̈̎̄̌̀́̔̍́̾͊̚͠͝о̵̧̡̱̳͕̝̫͈͙̦̞͓̺̻̘͉͍͎̥͇͖̖̰̤́̂͊̕͜͝ͅй̸̧͇͔̳̘̬̗̼͉̮̪̰̹̦̟͚̞̔̓́̽͋̆̓̍̃̎̈́̀̂̈͗̿̉͛̾̑̀ ̴̡̧̛͙̲̜͇̌̒̿̀́̉͋͂͑̓̋̇̚͜ͅт̶̛̭̎͊̑̿͛̏͆̀̓̌͋̍̂́̓̅̈̔͘̕͝е̷̡̛̜̰͚̱̮̂̄̓̈̒̔͊̐̀̈́̓̃̋͑̿͌͋̾͒͂̑̀́̍̆̌̽̕͘̚͠͝к̷̧̡̨̛̗̭̲̜͍̙̖̩̮̟̻͇̞͉͓̱͔̣̪͎̠̎̐̏̈́̀̉͛͌̾̌̋̅̍̒͒͊͗̀́͆̄̊͋͂̓͜͝͠ͅс̷̡̢̧̨̙͕̱̼͎̞̪͖͍̯̰̖̬̟͔̫̳̋̄͗̓̒̊̈́̓̍́̽͊̀т̸̡̨̧̮͙̫͎̳̲͓͚̣̞̠̻͉̟̯͔̭̩̝̼͍̥̺͖̪̇͜ͅ
^[[29;15R
pos1=1, pos2=15, delta=14
shdown ★★
()
Последнее исправление: shdown (всего исправлений: 1)
Ответ на: комментарий от gns

Автор предложения: нам пофиг на юникод, это будет то же самое, что и обычный strcmp.

Ты: а как же юникод?

И да, почитай драгонбук, а именно ту главу, в которой идет речь о конструировании конечных автоматов для разбора регексов.
Эффективный парсер со сложностью O(k) - это та же задача. Строки в case-блоках преобразуются в регекс и количество конечных состояний автомата соответствует количеству строк. Если сматчена одна из альтернатив, то вызывается функция из case-блока.

Да что ты такое несёшь?

d_root = {}

def insert(s, tag):
    d_cur = d_root
    for c in s:
        if c not in d_cur:
            d_cur[c] = {}
        d_cur = d_cur[c]
    d_cur[0] = tag

insert(b'abacaba', 1)
insert(b'abaaa', 2)
insert(b'bababa', 3)

def gen(d, offset):
    print(f'switch (str[{offset}]) ' + '{')
    for c, link in d.items():
        if c:
            print(f"case '{chr(c)}':")
            gen(link, offset + 1)
        else:
            print(f'case 0: code_for_tag_{link}();')
        print('goto done;')

    print('default: goto done;')
    print('}')

gen(d_root, 0)
print('done:')

Вот тебе генератор «эффективного парсера со сложностью O(k)». Каждый символ сравнивается не больше 256 (константа) раз.

shdown ★★
()
Ответ на: комментарий от shdown

Да легко.

Потрясающе! Раньше оно на Zalgo херню выдавало. Некоторые реализации, к слову, её выдают и очень криво рендерят такой текст.

Впрочем, на RTLO оно всё равно херню выдаст, так что в любом случае лучше юзать libicu.

yorshka
() автор топика
Ответ на: комментарий от yorshka

Впрочем, на RTLO оно всё равно херню выдаст, так что в любом случае лучше юзать libicu.

Какую ещё херню?

$ cat RTL.txt
English مرحباً بكم في الموقع More English
$ base64 < RTL.txt
RW5nbGlzaCDZhdix2K3YqNin2Ysg2KjZg9mFINmB2Yog2KfZhNmF2YjZgti5IE1vcmUgRW5nbGlz
aAo=
$ tcc -run foo.c < RTL.txt
40
$ bash test_otakoi.bash RTL.txt # оно теперь принимает файл первым аргументом, edit accordingly


^[[10;1R
English مرحباً بكم في الموقع More English
^[[12;41R
pos1=1, pos2=41, delta=40
$ 
shdown ★★
()
Ответ на: комментарий от shdown

Ну автомат как он есть. От каждого символа ты строишь таблицу переходов в зависимости от следующего за ним, если я правильно понимаю весь этот ВАш пистон. Один из вариантов строительства распознающих автоматов.

Мы чот друг друга не понимаем, походу.

gns ★★★★★
()
Ответ на: комментарий от gns

Ты:

в документе ничего не сказано о том, каким способом они предлагают реализовать эффективный парсер со сложностью O(k) вместо O(n*k), которую имеет цепочка условных операторов и strcmp.

Но этот способ очевиден любому. К чему ты это написал? К чему твои рассуждения о регулярных выражениях и dragon book?

shdown ★★
()
Ответ на: комментарий от shdown

К тому, что этот способ не самый оптимальный. Префиксные деревья — это хорошо, но это можно быстрее..И есть еще несколько способов минмизации таблицы переходов. Но это не отменяет того, что визуально одинаковые строки юникода могут иметь в себе разный набор бвйт. И тогда волшебство перестает работать.

gns ★★★★★
()
Ответ на: комментарий от yorshka

Как и в Си в целом. Живого кода с wchar_t я ни разу в жизни не видел, для обработки юникода обычно тащат libicu.

«Век живи, век учись», – подумал поручик. Я почему-то думал, что libicu исключительно для плюсов (наверное, потому, что во всех виденных мной примерах был плюсовый синтаксис с namespace-ми).

hobbit ★★★★★
()
Ответ на: комментарий от shdown

Блин, мне лень искать тот пример с black dot of death.

Ладно, держи, сам напросился:

$ cat emoji 
🤦🏼‍♂
$ ./foo < emoji 
5

Где теперь твой бо^Wwchar_t?

yorshka
() автор топика
Ответ на: комментарий от yorshka

АХАХАХАХАХ Firefox неправильно отрисовывает эту срань. Это один эмоджи, не два. Кстати, лишнее доказательство, что количество знакомест, занимаемых графемой, будет зависеть от шревта, рендера, браузера, погоды на Марсе и месячных твоей подружки.

Пруф: https://ibb.co/39rGzJ8J

Короче, в любом случае залупа и сишный wchar_t сосёт. Юзай libicu.

yorshka
() автор топика
Ответ на: комментарий от shdown

Это в urxvt. Решил запустить в модном alacritty — то же самое (только он отображает эти эмодзи, а в urxvt два квадратика и ‍male sign):

[~]-[%] echo $TERM
alacritty
[~]-[%] bash test_otakoi.bash foo.txt


^[[5;1R
🤦🏼‍♂
^[[7;6R
pos1=1, pos2=6, delta=5
[~]-[%]
shdown ★★
()
Последнее исправление: shdown (всего исправлений: 1)
Ответ на: комментарий от yorshka

У меня в немодном urxvt и модном alacritty оно занимает пять знакомест. При этом alacritty реально понимает и рисует эти эмодзи, а urxvt — нет.

Что за терминоль?

shdown ★★
()
Ответ на: комментарий от shdown

У меня в немодном urxvt и модном alacritty оно занимает пять знакомест.

Это неправильные терминалы и они неправильно реализуют юникод.

Что за терминоль?

Konsole.

yorshka
() автор топика

Сравнение строк

char*left="left", *right="right";
for(int i=0, j=0; i<strlen(left) && j<strlen(right); i++, j++)
    if (left[i]!=right[j])
        return false;
return true;

doomer
()
Последнее исправление: doomer (всего исправлений: 1)
Ответ на: комментарий от yorshka

Konsole.

Извини, куски кед себе в систему не буду тащить, у меня в прошлый раз от этого звук поломался и браузер какие-то странные вещи начал спрашивать при запуске.

А вообще я же специально выхлоп скрипта привёл, который замеряет реальное положение курсора. Запусти на своём этом файле “emoji”:

#!/usr/bin/env bash

get_cursor_column() {
    echo -e '\033[6n' >&2
    local res
    IFS= read -rd R res || return $?
    res=${res#*'['}
    res=${res#*;}
    echo "$res"
}

target_file=${1?}

# Каждый раз переводим строку с помощью echo без аргументов, потому что
# get_cursor_column в процессе работы передвигает курсор вправо.

# Замеряем позицию курсора в самом левом столбце (должно быть 1).
echo
pos1=$(get_cursor_column)

# Замеряем позицию курсора после вывода текста (но без '\n').
echo
echo -n "$(cat "$target_file")"
pos2=$(get_cursor_column)

echo
echo "pos1=$pos1, pos2=$pos2, delta=$(( pos2 - pos1 ))"

shdown ★★
()
Ответ на: комментарий от yorshka

это один символ, не пять

А можешь показать хоть один пример софта, кроме konsole, который воспринимает их как один символ? А то вот chromium рисует как два символа, firefox, ты говоришь, тоже, sublime text — тоже (при этом они в нём занимают пять знакомест — не знаю, куда скриншот загрузить).

shdown ★★
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.