На мой взгляд, макросы - это плохая привычка от C. Хотя они могут быть полезны для некоторых, я не вижу реальной потребности в них, когда есть typedefs и шаблоны. Шаблоны являются естественным продолжением объектно-ориентированного программирования. Вы можете сделать намного больше с шаблонами ...
Рассмотрим это ...
int main()
{
SimpleList lstA;
//...
SimpleList lstB = lstA; //would normally give an error after trying to compile
}
Чтобы сделать преобразование, вы можете использовать то, что называется конструктором преобразования и конструктор последовательности (посмотрите на конец) по довольно полному примеру для списка:
#include
template
class SimpleList
{
public:
typedef T value_type;
typedef std::size_t size_type;
private:
struct Knot
{
value_type val_;
Knot * next_;
Knot(const value_type &val)
:val_(val), next_(0)
{}
};
Knot * head_;
size_type nelems_;
public:
//Default constructor
SimpleList() throw()
:head_(0), nelems_(0)
{}
bool empty() const throw()
{ return size() == 0; }
size_type size() const throw()
{ return nelems_; }
private:
Knot * last() throw() //could be done better
{
if(empty()) return 0;
Knot *p = head_;
while (p->next_)
p = p->next_;
return p;
}
public:
void push_back(const value_type & val)
{
Knot *p = last();
if(!p)
head_ = new Knot(val);
else
p->next_ = new Knot(val);
++nelems_;
}
void clear() throw()
{
while(head_)
{
Knot *p = head_->next_;
delete head_;
head_ = p;
}
nelems_ = 0;
}
//Destructor:
~SimpleList() throw()
{ clear(); }
//Iterators:
class iterator
{
Knot * cur_;
public:
iterator(Knot *p) throw()
:cur_(p)
{}
bool operator==(const iterator & iter)const throw()
{ return cur_ == iter.cur_; }
bool operator!=(const iterator & iter)const throw()
{ return !(*this == iter); }
iterator & operator++()
{
cur_ = cur_->next_;
return *this;
}
iterator operator++(int)
{
iterator temp(*this);
operator++();
return temp;
}
value_type & operator*()throw()
{ return cur_->val_; }
value_type operator*() const
{ return cur_->val_; }
value_type operator->()
{ return cur_->val_; }
const value_type operator->() const
{ return cur_->val_; }
};
iterator begin() throw()
{ return iterator(head_); }
iterator begin() const throw()
{ return iterator(head_); }
iterator end() throw()
{ return iterator(0); }
iterator end() const throw()
{ return iterator(0); }
//Copy constructor:
SimpleList(const SimpleList & lst)
:head_(0), nelems_(0)
{
for(iterator i = lst.begin(); i != lst.end(); ++i)
push_back(*i);
}
void swap(SimpleList & lst) throw()
{
std::swap(head_, lst.head_);
std::swap(nelems_, lst.nelems_);
}
SimpleList & operator=(const SimpleList & lst)
{
SimpleList(lst).swap(*this);
return *this;
}
//Conversion constructor
template
SimpleList(const SimpleList &lst)
:head_(0), nelems_(0)
{
for(typename SimpleList::iterator iter = lst.begin(); iter != lst.end(); ++iter)
push_back(*iter);
}
template
SimpleList & operator=(const SimpleList &lst)
{
SimpleList(lst).swap(*this);
return *this;
}
//Sequence constructor:
template
SimpleList(Iter first, Iter last)
:head_(0), nelems_(0)
{
for(;first!=last; ++first)
push_back(*first);
}
};
Посмотрите на информацию cplusplus.com на шаблоны ! Вы можете использовать шаблоны для выполнения так называемых черт, которые используются, имеет своего рода документацию для типов и т. Д. Вы можете сделать гораздо больше с шаблонами, чем возможно с помощью макросов!
Вот возможное решение с использованием Perl:
perl -pe 'if (/│.*└/) { print; s/ *└.*// }'
Идея:
Для каждой строки, содержащей где-нибудь после │
и └
, обрежьте └
и все последующие символы и все предшествующие пробелы, затем выведите эту измененную строку.
Эффект:
│ │ └── foo.xyz
будет сопровождаться новой строкой, содержащей только
│ │
на выходе.
Sed версия:
sed '/│.*└/{p;s/ *└.*//}'
Для вашего образца ввода он производит следующий вывод:
$ tree -F -a --dirsfirst project
project
├── my_app/
│ └── __init__.py
│
└── tests/
├── integration/
│ ├── __init__.py
│ └── test_integration.py
│
└── unit/
├── __init__.py
└── test_sum.py
$ tree -F -a --dirsfirst helloworld
helloworld
├── helloworld/
│ ├── __init__.py
│ ├── helloworld.py
│ └── helpers.py
│
├── tests/
│ ├── helloworld_tests.py
│ └── helpers_tests.py
│
├── .gitignore
├── LICENSE
├── README.md
├── requirements.txt
└── setup.py
Это может работать для вас (GNU sed):
sed 's/\(.*│\)\s*└──.*/&\n\1/' file
Где файл может быть stdin из канала команды дерева, например
tree -Fa --dirsfirst helloworld | sed 's/\(.*│\)\s*└──.*/&\n\1/'
Использование cat file
вместо двух команд дерева в вашем вопросе с GNU awk:
$ cat file | awk '1; match([110],/^((\s*│)+)\s+└/,a){ print a[1] }'
project
├── my_app/
│ └── __init__.py
│
└── tests/
├── integration/
│ ├── __init__.py
│ └── test_integration.py
│
└── unit/
├── __init__.py
└── test_sum.py
helloworld
├── helloworld/
│ ├── __init__.py
│ ├── helloworld.py
│ └── helpers.py
│
├── tests/
│ ├── helloworld_tests.py
│ └── helpers_tests.py
│
├── .gitignore
├── LICENSE
├── README.md
├── requirements.txt
└── setup.py
и с любым awk:
$ cat file | awk '1; match([111],/^[[:space:]]*(│[[:space:]]+)+└/){ print substr([111],1,RLENGTH-1) }'
и с GNU sed: [ 116]
$ cat file | sed -En 'p; s/^((\s*│)+)\s+└.*/\1/p'