LINUX.ORG.RU

Есть ли аналог текстовых подстановок в Bash (через фигурные скобки) в C/C++?


0

2

Ищу либу или исходники, где уже есть реализовано текстовые подстановки в стиле Bash.

Пример на Bash (украденный когда-то из ЛОРа)

echo л{и,ы,у,я,е,ей,ю,юй,а,ай}{н,нн,л,лл,п}{у,а,е,и,ай,ю,я}{кс,ксь,пс,псь,с,сь,ц,х}

Как (а точнее чем) такое бы можно было сделать на C/C++?

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

★★★★★

Последнее исправление: Chaser_Andrey (всего исправлений: 1)

омг, бери стандарт, изучай синтаксис
такой высокоуровневой фигни в седствах низкоуровнего с нет
значит нужна либа

ну или popen(«bash», …
ты понел

anonymous
()

Циклы не предлагать … получается просто невообразимо ужасный и совершенно негибкий.

вынеси его в отдельный модуль, очевидно же

anonymous
()

Реализуется за 15 минут.

note173 ★★★★★
()

На С++11 - как-нибудь так, например:

#include <iostream>
#include <vector>
#include <functional>
#include <locale>

class StringGen {
    typedef std::vector<std::vector<std::wstring>> Vec;
    typedef Vec::const_iterator Iter;
    Iter beg, end;
    StringGen(Iter b, Iter e) : beg(b), end(e) {}

    public:
    StringGen(const Vec& v) : beg(v.begin()), end(v.end()) {}

    void each(std::function<void(std::wstring str)> f) {
        if (beg == end) {
            f(L"");
        } else {
            StringGen(beg, --end).each([&](std::wstring prefix) {
                for (const auto& s : *end)
                    f(prefix + s);
            });
        }
    }
};

int main() {
    const std::locale loc("ru_RU.UTF-8");
    std::locale::global(loc);

    StringGen({{L"л"},
               {L"и",L"ы",L"у",L"я",L"е",L"ей",L"ю",L"юй",L"а",L"ай"},
               {L"н",L"нн",L"л",L"лл",L"п"},
               {L"у",L"а",L"е",L"и",L"ай",L"ю",L"я"},
               {L"кс",L"ксь",L"пс",L"псь",L"с",L"сь",L"ц",L"х"}}).each 
              ([](std::wstring str) { std::wcout << str << '\n'; });
}

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

кокой кошмар
хорошо, что я в своё время не взялся за плюсы

anonymous
()

а питон чем не устраивает?

#!/usr/bin/python2.6
# -*- coding: utf-8 -*-


lists = [[u'и',u'ы',u'у',u'я',u'е',u'ей',u'ю',u'юй',u'а',u'ай'],
         [u'н',u'нн',u'л',u'лл',u'п'],
         [u'у',u'а',u'е',u'и',u'ай',u'ю',u'я'],
         [u'кс',u'ксь',u'пс',u'псь',u'с',u'сь',u'ц',u'х']]

lists2 = []

trackers = {}

def r(lists, lists2, trackers, level, depth):

    for i in lists[level]:

        trackers[level] = i

        if level != depth-1:
            r(lists, lists2, trackers, level+1, depth)
        else:
            word = u'л'
            for j in trackers.keys():
                word += trackers[j]
            lists2.append(word)

r(lists, lists2, trackers, 0, len(lists))

for i in lists2:
    print i.encode('utf-8')

AGUtilities ★★★
()

люблю такие треды :)

#include <stdio.h>
#include <string.h>

static void foo(const char **l[]) {
    int i, n;
    for (n = 0; l[n]; ++n);
    int s[n];
    memset(s, 0, sizeof s);
    do {
        for (i = 0; i < n; ++i)
            fputs(l[i][s[i]], stdout);
        putchar('\n');
        for (i = 0; i < n && l[i][++s[i]] == NULL; s[i++] = 0);
    } while (i < n);
}

int main() {
    foo((const char**[]) {
        (const char*[]) { "л", NULL },
        (const char*[]) { "и", "ы", "у", "я", "е", "ей", "ю", "юй", "а", "ай", NULL },
        (const char*[]) { "н", "нн", "л", "лл", "п", NULL },
        (const char*[]) { "у", "а", "е", "и", "ай", "ю", "я", NULL },
        (const char*[]) { "кс", "ксь", "пс", "псь", "с", "сь", "ц", "х", NULL },
        NULL
    });
}
gcc -std=c99 -W -Wall -Wextra -pedantic test.c
arsi ★★★★★
()
cout << gen("л").gen("и,ы,у,я,е,ей,ю,юй,а,ай").gen("н,нн,л,лл,п").gen("у,а,е,и,ай,ю,я").gen("кс,ксь,пс,псь,с,сь,ц,х");

Реализацию gen() и класс-хелпер сам напишешь, не маленький.

Да, господа выше по треду, которые для решения такой задачи ворочают конструкциями типа

        (const char*[]) { "и", "ы", "у", "я", "е", "ей", "ю", "юй", "а", "ай", NULL },
У вас Си++ головного мозга. Пора в санаторий.

geekless ★★
()
Ответ на: комментарий от Trashman
infixr 5 +++
(+++) = liftM2 (++)
["л"]+++["и","ы","у","я","е","ей","ю","юй","а","ай"]+++["н","нн","л","лл","п"]+++["у","а","е","и","ай","ю","я"]+++["кс","ксь","пс","псь","с","сь","ц","х"]
Miguel ★★★★★
()
Ответ на: комментарий от Trashman
import Control.Applicative
foldl1 (\x -> \y -> (++) <$> x <*> y)  [["л"],["и","ы","у","я","е","ей","ю","юй","а","ай"],["н","нн","л","лл","п"],["у","а","е","и","ай","ю","я"],["кс","ксь","пс","псь","с","сь","ц","х"]]
anarquista ★★★★★
()
Ответ на: комментарий от geekless
gen("л").gen("и,ы,у,я,е,ей,ю,юй,а,ай").gen("н,нн,л,лл,п").gen("у,а,е,и,ай,ю,я").gen("кс,ксь,пс,псь,с,сь,ц,х");

И да, Ъ С++ было бы так:

 gen({"л"})
  .gen({"и" , "ы", "у", "я", "е", "ей", "ю", "юй", "а", "ай" })
  .gen({"н", "нн", "л", "лл", "п" })
  .gen({ "у", "а", "е", "и", "ай", "ю", "я" })
  .gen({ "кс", "ксь", "пс", "псь", "с", "сь", "ц", "х" });
Begemoth ★★★★★
()

осталось запостить валидный плюсовой код:

std::cout << XString<'Hell','o, w', 'orld', '! Do', 'nt w', 'arry', ' be ', 'happ', 'y!  ', XString<'Hell', 'yeah'> >::chars() << std::endl;

и спеть про mpl::string, Сxx11 и велосипеды :)

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

питон

Бгг.

#!/usr/bin/env ruby
#coding: utf-8

puts [%w'л', %w'и ы у я е ей ю юй а ай', %w'н нн л лл п', %w'у а е и ай ю я', %w'кс ксь пс псь с сь ц х'].reduce(['']) { |m , v|
	m.map { |v1| v.map { |v2| v1 + v2} }.flatten
}

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

Ты хотел сказать C головного мозга?

В данном случае принципиальной разницы нет. У первого отменившегося — Си++, у второго Си.

geekless ★★
()
Ответ на: комментарий от arsi
test.c: In function 'foo':
test.c:11:29: error: expected ')' before ']' token
test.c:11:29: error: too few arguments to function 'fputs'
test.c:11:29: error: expected ';' before ']' token
test.c:11:29: error: expected statement before ']' token
test.c:11:30: error: expected expression before ',' token
test.c:11:30: warning: left-hand operand of comma expression has no effect [-Wunused-value]
test.c:11:30: warning: statement with no effect [-Wunused-value]
test.c:11:38: error: expected statement before ')' token
test.c:13:42: error: expected ';' before ']' token
test.c:13:42: error: expected expression before ']' token
test.c:13:42: error: expected statement before ']' token
test.c:13:44: error: expected expression before '==' token
test.c:13:63: error: expected ';' before ')' token
test.c:13:63: error: expected statement before ')' token
anarquista ★★★★★
()
Ответ на: комментарий от lomereiter

да ещё некоторые вложены

А где вложенность?

anonymous
()
Ответ на: комментарий от anarquista

эх, а говорил «проще, понятнее»…

perl6 -e 'say <л> X~ <и ы у я е ей ю юй а ай> X~ <н нн л лл п> X~ <у а е и ай ю я> X~ <кс ксь пс псь с сь ц х>'
arsi ★★★★★
()
Ответ на: комментарий от geekless

#!/usr/bin/python

from functools import reduce

print (reduce (lambda x,y: [a + b for a in x for b in y], [[«л»],[«и»,«ы»,«у»,«я»,«е»,«ей»,«ю»,«юй»,«а»,«ай»],[«н»,«нн»,«л»,«лл»,«п»],[«у»,«а»,«е»,«и»,«ай»,«ю»,«я»],[«кс»,«ксь»,«пс»,«псь»,«с»,«сь»,«ц»,«х»]] ))

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

шучу я. успокойся.

/me вообще не сильно напрягал мозг в пять часов ночи то

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

Как из списка списков получить список более интуитивным способом, чем функцией reduce?

Как из двух списков получить один более интуитивным способом, чем с помощью конструкции List comprehensions?

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

Кстати. Либо я не слишком хорошо знаю ruby, либо там действительно нет удобного аналога для a + b for a in x for b in y из твоего примера.

Если в самом деле нет, надо бы запилить новый метод, чтобы делать:

[x, y].for{|a, b| a + b}

geekless ★★
()

[code=lua] #!/usr/bin/env lua

local function gen(t1, t2, ...) if not t2 then return t1 end local t = {} for _, v1 in ipairs(t1) do for _, v2 in ipairs(t2) do table.insert(t, v1 .. v2) end end return gen(t, ...) end

print(table.concat(gen({«л»}, {«и»,«ы»,«у»,«я»,«е»,«ей»,«ю»,«юй»,«а»,«ай»}, {«н»,«нн»,«л»,«лл»,«п»}, {«у»,«а»,«е»,«и»,«ай»,«ю»,«я»}, {«кс»,«ксь»,«пс»,«псь»,«с»,«сь»,«ц»,«х»}), '\n')) [/code]

anonymous
()
Ответ на: комментарий от geekless

Лень писать же, пусть машина сама парсит.

А потом понадобится использовать запятую не в качестве разделителя и потребуется добавлять экранирование, не нужное усложнение, которого можно избежать.

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

Какая мерзость эти ваши однострочники.

(defun permut (l)
  (reduce
   (λ (acc elt)
     (mapcan
      (λ (e)
        (mapcar (λ (a) (format nil "~a~a" a e)) acc))
      elt))
   l))

Так гораздо лучше и понятнее.

ugoday ★★★★★
()

Кстати про С++ГМ:

vector<string> operator "" templ(const char *inTemplate, size_t inNumChars)
{
// generate strings
...
}

int main()
{
  for (string s : "{0,1}{0,1}b"templ)
    cout << s << endl;
}

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

А потом понадобится использовать запятую не в качестве разделителя и потребуется добавлять экранирование, не нужное усложнение, которого можно избежать.

Ну так можно объявить и gen(const char * *) , и gen(const char *).

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

Мужик сказал, мужик сделал. «Интуитивный способ» :-D

#!/usr/bin/env ruby
#coding: utf-8

class Array
	def formap(&block)
		if size == 1
			self[0].map(&block)
		elsif size > 1
			self[0].map { |v1|
				self[1..(size-1)].formap { |*v2|
					block.call(*v2.unshift(v1))
				}
			}
		end
	end
end

puts [%w'л', %w'и ы у я е ей ю юй а ай', %w'н нн л лл п', %w'у а е и ай ю я', %w'кс ксь пс псь с сь ц х'].formap { |*v| v.join }
geekless ★★
()

Спасибо всем отписавшимся! Из треда подчерпнул немало интересной и полезной информации.

Chaser_Andrey ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.