3 * Copyright (c) 1998-2002
6 * Use, modification and distribution are subject to the
7 * Boost Software License, Version 1.0. (See accompanying file
8 * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
13 * LOCATION: see http://www.boost.org for most recent version.
14 * FILE regex_format.hpp
15 * VERSION see <boost/version.hpp>
16 * DESCRIPTION: Provides formatting output routines for search and replace
17 * operations. Note this is an internal header file included
18 * by regex.hpp, do not include on its own.
21 #ifndef BOOST_REGEX_FORMAT_HPP
22 #define BOOST_REGEX_FORMAT_HPP
27 #ifdef BOOST_HAS_ABI_HEADERS
28 # include BOOST_ABI_PREFIX
32 // Forward declaration:
34 template <class BidiIterator, class Allocator = BOOST_DEDUCED_TYPENAME std::vector<sub_match<BidiIterator> >::allocator_type >
40 // struct trivial_format_traits:
41 // defines minimum localisation support for formatting
42 // in the case that the actual regex traits is unavailable.
44 template <class charT>
45 struct trivial_format_traits
47 typedef charT char_type;
49 static std::ptrdiff_t length(const charT* p)
51 return global_length(p);
53 static charT tolower(charT c)
55 return ::boost::re_detail::global_lower(c);
57 static charT toupper(charT c)
59 return ::boost::re_detail::global_upper(c);
61 static int value(const charT c, int radix)
63 int result = global_value(c);
64 return result >= radix ? -1 : result;
66 int toi(const charT*& p1, const charT* p2, int radix)const
68 return global_toi(p1, p2, radix, *this);
72 template <class OutputIterator, class Results, class traits>
73 class basic_regex_formatter
76 typedef typename traits::char_type char_type;
77 basic_regex_formatter(OutputIterator o, const Results& r, const traits& t)
78 : m_traits(t), m_results(r), m_out(o), m_state(output_copy), m_have_conditional(false) {}
79 OutputIterator format(const char_type* p1, const char_type* p2, match_flag_type f);
80 OutputIterator format(const char_type* p1, match_flag_type f)
82 return format(p1, p1 + m_traits.length(p1), f);
85 typedef typename Results::value_type sub_match_type;
96 void put(char_type c);
97 void put(const sub_match_type& sub);
100 void format_escape();
101 void format_conditional();
102 void format_until_scope_end();
104 const traits& m_traits; // the traits class for localised formatting operations
105 const Results& m_results; // the match_results being used.
106 OutputIterator m_out; // where to send output.
107 const char_type* m_position; // format string, current position
108 const char_type* m_end; // format string end
109 match_flag_type m_flags; // format flags to use
110 output_state m_state; // what to do with the next character
111 bool m_have_conditional; // we are parsing a conditional
113 basic_regex_formatter(const basic_regex_formatter&);
114 basic_regex_formatter& operator=(const basic_regex_formatter&);
117 template <class OutputIterator, class Results, class traits>
118 OutputIterator basic_regex_formatter<OutputIterator, Results, traits>::format(const char_type* p1, const char_type* p2, match_flag_type f)
127 template <class OutputIterator, class Results, class traits>
128 void basic_regex_formatter<OutputIterator, Results, traits>::format_all()
131 while(m_position != m_end)
136 if(m_flags & ::boost::regex_constants::format_sed)
148 if(m_flags & boost::regex_constants::format_all)
151 bool have_conditional = m_have_conditional;
152 m_have_conditional = false;
153 format_until_scope_end();
154 m_have_conditional = have_conditional;
155 if(m_position == m_end)
157 BOOST_ASSERT(*m_position == static_cast<char_type>(')'));
158 ++m_position; // skip the closing ')'
165 if(m_flags & boost::regex_constants::format_all)
173 if((m_flags & boost::regex_constants::format_all) && m_have_conditional)
181 if(m_flags & boost::regex_constants::format_all)
184 format_conditional();
191 if((m_flags & format_sed) == 0)
196 // fall through, not a special character:
205 template <class OutputIterator, class Results, class traits>
206 void basic_regex_formatter<OutputIterator, Results, traits>::format_perl()
209 // On entry *m_position points to a '$' character
210 // output the information that goes with it:
212 BOOST_ASSERT(*m_position == '$');
214 // see if this is a trailing '$':
216 if(++m_position == m_end)
224 // OK find out what kind it is:
230 put(this->m_results[0]);
234 put(this->m_results.prefix());
238 put(this->m_results.suffix());
244 // see if we have a number:
246 std::ptrdiff_t len = (std::min)(static_cast<std::ptrdiff_t>(2), ::boost::re_detail::distance(m_position, m_end));
247 int v = m_traits.toi(m_position, m_position + len, 10);
250 // leave the $ as is, and carry on:
256 // otherwise output sub v:
257 put(this->m_results[v]);
262 template <class OutputIterator, class Results, class traits>
263 void basic_regex_formatter<OutputIterator, Results, traits>::format_escape()
265 // skip the escape and check for trailing escape:
266 if(++m_position == m_end)
268 put(static_cast<char_type>('\\'));
271 // now switch on the escape type:
275 put(static_cast<char_type>('\a'));
279 put(static_cast<char_type>('\f'));
283 put(static_cast<char_type>('\n'));
287 put(static_cast<char_type>('\r'));
291 put(static_cast<char_type>('\t'));
295 put(static_cast<char_type>('\v'));
299 if(++m_position == m_end)
301 put(static_cast<char_type>('x'));
304 // maybe have \x{ddd}
305 if(*m_position == static_cast<char_type>('{'))
308 int val = m_traits.toi(m_position, m_end, 16);
311 // invalid value treat everything as literals:
312 put(static_cast<char_type>('x'));
313 put(static_cast<char_type>('{'));
316 if(*m_position != static_cast<char_type>('}'))
318 while(*m_position != static_cast<char_type>('\\'))
325 put(static_cast<char_type>(val));
330 std::ptrdiff_t len = (std::min)(static_cast<std::ptrdiff_t>(2), ::boost::re_detail::distance(m_position, m_end));
331 int val = m_traits.toi(m_position, m_position + len, 16);
338 put(static_cast<char_type>(val));
342 if(++m_position == m_end)
348 put(static_cast<char_type>(*m_position++ % 32));
351 put(static_cast<char_type>(27));
355 // see if we have a perl specific escape:
356 if((m_flags & boost::regex_constants::format_sed) == 0)
358 bool breakout = false;
363 m_state = output_next_lower;
368 m_state = output_lower;
373 m_state = output_next_upper;
378 m_state = output_upper;
383 m_state = output_copy;
390 // see if we have a \n sed style backreference:
391 int v = m_traits.toi(m_position, m_position+1, 10);
392 if((v > 0) || ((v == 0) && (m_flags & ::boost::regex_constants::format_sed)))
399 // octal ecape sequence:
401 std::ptrdiff_t len = (std::min)(static_cast<std::ptrdiff_t>(4), ::boost::re_detail::distance(m_position, m_end));
402 v = m_traits.toi(m_position, m_position + len, 8);
403 BOOST_ASSERT(v >= 0);
404 put(static_cast<char_type>(v));
407 // Otherwise output the character "as is":
413 template <class OutputIterator, class Results, class traits>
414 void basic_regex_formatter<OutputIterator, Results, traits>::format_conditional()
416 if(m_position == m_end)
418 // oops trailing '?':
419 put(static_cast<char_type>('?'));
422 std::ptrdiff_t len = (std::min)(static_cast<std::ptrdiff_t>(2), ::boost::re_detail::distance(m_position, m_end));
423 int v = m_traits.toi(m_position, m_position + len, 10);
426 // oops not a number:
427 put(static_cast<char_type>('?'));
431 // output varies depending upon whether sub-expression v matched or not:
432 if(m_results[v].matched)
434 m_have_conditional = true;
436 m_have_conditional = false;
437 if((m_position != m_end) && (*m_position == static_cast<char_type>(':')))
441 // save output state, then turn it off:
442 output_state saved_state = m_state;
443 m_state = output_none;
444 // format the rest of this scope:
445 format_until_scope_end();
446 // restore output state:
447 m_state = saved_state;
452 // save output state, then turn it off:
453 output_state saved_state = m_state;
454 m_state = output_none;
455 // format until ':' or ')':
456 m_have_conditional = true;
458 m_have_conditional = false;
460 m_state = saved_state;
461 if((m_position != m_end) && (*m_position == static_cast<char_type>(':')))
465 // format the rest of this scope:
466 format_until_scope_end();
471 template <class OutputIterator, class Results, class traits>
472 void basic_regex_formatter<OutputIterator, Results, traits>::format_until_scope_end()
477 if((m_position == m_end) || (*m_position == static_cast<char_type>(')')))
480 }while(m_position != m_end);
483 template <class OutputIterator, class Results, class traits>
484 void basic_regex_formatter<OutputIterator, Results, traits>::put(char_type c)
486 // write a single character to output
487 // according to which case translation mode we are in:
488 switch(this->m_state)
492 case output_next_lower:
493 c = m_traits.tolower(c);
494 this->m_state = output_copy;
496 case output_next_upper:
497 c = m_traits.toupper(c);
498 this->m_state = output_copy;
501 c = m_traits.tolower(c);
504 c = m_traits.toupper(c);
513 template <class OutputIterator, class Results, class traits>
514 void basic_regex_formatter<OutputIterator, Results, traits>::put(const sub_match_type& sub)
516 typedef typename sub_match_type::iterator iterator_type;
517 iterator_type i = sub.first;
518 while(i != sub.second)
526 class string_out_iterator
527 #ifndef BOOST_NO_STD_ITERATOR
528 : public std::iterator<std::output_iterator_tag, typename S::value_type>
533 string_out_iterator(S& s) : out(&s) {}
534 string_out_iterator& operator++() { return *this; }
535 string_out_iterator& operator++(int) { return *this; }
536 string_out_iterator& operator*() { return *this; }
537 string_out_iterator& operator=(typename S::value_type v)
543 #ifdef BOOST_NO_STD_ITERATOR
544 typedef std::ptrdiff_t difference_type;
545 typedef typename S::value_type value_type;
546 typedef value_type* pointer;
547 typedef value_type& reference;
548 typedef std::output_iterator_tag iterator_category;
552 template <class OutputIterator, class Iterator, class Alloc, class charT, class traits>
553 OutputIterator regex_format_imp(OutputIterator out,
554 const match_results<Iterator, Alloc>& m,
555 const charT* p1, const charT* p2,
556 match_flag_type flags,
560 if(flags & regex_constants::format_literal)
562 return re_detail::copy(p1, p2, out);
565 re_detail::basic_regex_formatter<
567 match_results<Iterator, Alloc>,
568 traits > f(out, m, t);
569 return f.format(p1, p2, flags);
573 } // namespace re_detail
575 template <class OutputIterator, class Iterator, class charT>
576 OutputIterator regex_format(OutputIterator out,
577 const match_results<Iterator>& m,
579 match_flag_type flags = format_all
582 re_detail::trivial_format_traits<charT> traits;
583 return re_detail::regex_format_imp(out, m, fmt, fmt + traits.length(fmt), flags, traits);
586 template <class OutputIterator, class Iterator, class charT>
587 OutputIterator regex_format(OutputIterator out,
588 const match_results<Iterator>& m,
589 const std::basic_string<charT>& fmt,
590 match_flag_type flags = format_all
593 re_detail::trivial_format_traits<charT> traits;
594 return re_detail::regex_format_imp(out, m, fmt.data(), fmt.data() + fmt.size(), flags, traits);
597 template <class Iterator, class charT>
598 std::basic_string<charT> regex_format(const match_results<Iterator>& m,
600 match_flag_type flags = format_all)
602 std::basic_string<charT> result;
603 re_detail::string_out_iterator<std::basic_string<charT> > i(result);
604 re_detail::trivial_format_traits<charT> traits;
605 re_detail::regex_format_imp(i, m, fmt, fmt + traits.length(fmt), flags, traits);
609 template <class Iterator, class charT>
610 std::basic_string<charT> regex_format(const match_results<Iterator>& m,
611 const std::basic_string<charT>& fmt,
612 match_flag_type flags = format_all)
614 std::basic_string<charT> result;
615 re_detail::string_out_iterator<std::basic_string<charT> > i(result);
616 re_detail::trivial_format_traits<charT> traits;
617 re_detail::regex_format_imp(i, m, fmt.data(), fmt.data() + fmt.size(), flags, traits);
621 #ifdef BOOST_HAS_ABI_HEADERS
622 # include BOOST_ABI_SUFFIX
627 #endif // BOOST_REGEX_FORMAT_HPP