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
29 #pragma warning(disable: 4103)
31 #ifdef BOOST_HAS_ABI_HEADERS
32 # include BOOST_ABI_PREFIX
39 // Forward declaration:
41 template <class BidiIterator, class Allocator = BOOST_DEDUCED_TYPENAME std::vector<sub_match<BidiIterator> >::allocator_type >
47 // struct trivial_format_traits:
48 // defines minimum localisation support for formatting
49 // in the case that the actual regex traits is unavailable.
51 template <class charT>
52 struct trivial_format_traits
54 typedef charT char_type;
56 static std::ptrdiff_t length(const charT* p)
58 return global_length(p);
60 static charT tolower(charT c)
62 return ::boost::re_detail::global_lower(c);
64 static charT toupper(charT c)
66 return ::boost::re_detail::global_upper(c);
68 static int value(const charT c, int radix)
70 int result = global_value(c);
71 return result >= radix ? -1 : result;
73 int toi(const charT*& p1, const charT* p2, int radix)const
75 return global_toi(p1, p2, radix, *this);
79 template <class OutputIterator, class Results, class traits>
80 class basic_regex_formatter
83 typedef typename traits::char_type char_type;
84 basic_regex_formatter(OutputIterator o, const Results& r, const traits& t)
85 : m_traits(t), m_results(r), m_out(o), m_state(output_copy), m_restore_state(output_copy), m_have_conditional(false) {}
86 OutputIterator format(const char_type* p1, const char_type* p2, match_flag_type f);
87 OutputIterator format(const char_type* p1, match_flag_type f)
89 return format(p1, p1 + m_traits.length(p1), f);
92 typedef typename Results::value_type sub_match_type;
103 void put(char_type c);
104 void put(const sub_match_type& sub);
107 void format_escape();
108 void format_conditional();
109 void format_until_scope_end();
110 bool handle_perl_verb(bool have_brace);
112 const traits& m_traits; // the traits class for localised formatting operations
113 const Results& m_results; // the match_results being used.
114 OutputIterator m_out; // where to send output.
115 const char_type* m_position; // format string, current position
116 const char_type* m_end; // format string end
117 match_flag_type m_flags; // format flags to use
118 output_state m_state; // what to do with the next character
119 output_state m_restore_state; // what state to restore to.
120 bool m_have_conditional; // we are parsing a conditional
122 basic_regex_formatter(const basic_regex_formatter&);
123 basic_regex_formatter& operator=(const basic_regex_formatter&);
126 template <class OutputIterator, class Results, class traits>
127 OutputIterator basic_regex_formatter<OutputIterator, Results, traits>::format(const char_type* p1, const char_type* p2, match_flag_type f)
136 template <class OutputIterator, class Results, class traits>
137 void basic_regex_formatter<OutputIterator, Results, traits>::format_all()
140 while(m_position != m_end)
145 if(m_flags & ::boost::regex_constants::format_sed)
157 if(m_flags & boost::regex_constants::format_all)
160 bool have_conditional = m_have_conditional;
161 m_have_conditional = false;
162 format_until_scope_end();
163 m_have_conditional = have_conditional;
164 if(m_position == m_end)
166 BOOST_ASSERT(*m_position == static_cast<char_type>(')'));
167 ++m_position; // skip the closing ')'
174 if(m_flags & boost::regex_constants::format_all)
182 if((m_flags & boost::regex_constants::format_all) && m_have_conditional)
190 if(m_flags & boost::regex_constants::format_all)
193 format_conditional();
200 if((m_flags & format_sed) == 0)
205 // fall through, not a special character:
214 template <class OutputIterator, class Results, class traits>
215 void basic_regex_formatter<OutputIterator, Results, traits>::format_perl()
218 // On entry *m_position points to a '$' character
219 // output the information that goes with it:
221 BOOST_ASSERT(*m_position == '$');
223 // see if this is a trailing '$':
225 if(++m_position == m_end)
233 // OK find out what kind it is:
235 bool have_brace = false;
236 const char_type* save_position = m_position;
241 put(this->m_results[0]);
245 put(this->m_results.prefix());
249 put(this->m_results.suffix());
255 if((++m_position != m_end) && (*m_position == '{'))
257 const char_type* base = ++m_position;
258 while((m_position != m_end) && (*m_position != '}')) ++m_position;
259 if(m_position != m_end)
261 // Named sub-expression:
262 put(this->m_results.named_subexpression(base, m_position));
271 put((this->m_results)[this->m_results.size() > 1 ? this->m_results.size() - 1 : 1]);
278 // see if we have a number:
280 std::ptrdiff_t len = ::boost::re_detail::distance(m_position, m_end);
281 //len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
282 int v = m_traits.toi(m_position, m_position + len, 10);
283 if((v < 0) || (have_brace && ((m_position == m_end) || (*m_position != '}'))))
285 // Look for a Perl-5.10 verb:
286 if(!handle_perl_verb(have_brace))
288 // leave the $ as is, and carry on:
289 m_position = --save_position;
295 // otherwise output sub v:
296 put(this->m_results[v]);
303 template <class OutputIterator, class Results, class traits>
304 bool basic_regex_formatter<OutputIterator, Results, traits>::handle_perl_verb(bool have_brace)
307 // We may have a capitalised string containing a Perl action:
309 static const char_type MATCH[] = { 'M', 'A', 'T', 'C', 'H' };
310 static const char_type PREMATCH[] = { 'P', 'R', 'E', 'M', 'A', 'T', 'C', 'H' };
311 static const char_type POSTMATCH[] = { 'P', 'O', 'S', 'T', 'M', 'A', 'T', 'C', 'H' };
312 static const char_type LAST_PAREN_MATCH[] = { 'L', 'A', 'S', 'T', '_', 'P', 'A', 'R', 'E', 'N', '_', 'M', 'A', 'T', 'C', 'H' };
313 static const char_type LAST_SUBMATCH_RESULT[] = { 'L', 'A', 'S', 'T', '_', 'S', 'U', 'B', 'M', 'A', 'T', 'C', 'H', '_', 'R', 'E', 'S', 'U', 'L', 'T' };
314 static const char_type LAST_SUBMATCH_RESULT_ALT[] = { '^', 'N' };
316 if(have_brace && (*m_position == '^'))
319 int max_len = m_end - m_position;
321 if((max_len >= 5) && std::equal(m_position, m_position + 5, MATCH))
326 if(*m_position == '}')
334 put(this->m_results[0]);
337 if((max_len >= 8) && std::equal(m_position, m_position + 8, PREMATCH))
342 if(*m_position == '}')
350 put(this->m_results.prefix());
353 if((max_len >= 9) && std::equal(m_position, m_position + 9, POSTMATCH))
358 if(*m_position == '}')
366 put(this->m_results.suffix());
369 if((max_len >= 16) && std::equal(m_position, m_position + 16, LAST_PAREN_MATCH))
374 if(*m_position == '}')
382 put((this->m_results)[this->m_results.size() > 1 ? this->m_results.size() - 1 : 1]);
385 if((max_len >= 20) && std::equal(m_position, m_position + 20, LAST_SUBMATCH_RESULT))
390 if(*m_position == '}')
398 put(this->m_results.get_last_closed_paren());
401 if((max_len >= 2) && std::equal(m_position, m_position + 2, LAST_SUBMATCH_RESULT_ALT))
406 if(*m_position == '}')
414 put(this->m_results.get_last_closed_paren());
420 template <class OutputIterator, class Results, class traits>
421 void basic_regex_formatter<OutputIterator, Results, traits>::format_escape()
423 // skip the escape and check for trailing escape:
424 if(++m_position == m_end)
426 put(static_cast<char_type>('\\'));
429 // now switch on the escape type:
433 put(static_cast<char_type>('\a'));
437 put(static_cast<char_type>('\f'));
441 put(static_cast<char_type>('\n'));
445 put(static_cast<char_type>('\r'));
449 put(static_cast<char_type>('\t'));
453 put(static_cast<char_type>('\v'));
457 if(++m_position == m_end)
459 put(static_cast<char_type>('x'));
462 // maybe have \x{ddd}
463 if(*m_position == static_cast<char_type>('{'))
466 int val = m_traits.toi(m_position, m_end, 16);
469 // invalid value treat everything as literals:
470 put(static_cast<char_type>('x'));
471 put(static_cast<char_type>('{'));
474 if(*m_position != static_cast<char_type>('}'))
476 while(*m_position != static_cast<char_type>('\\'))
483 put(static_cast<char_type>(val));
488 std::ptrdiff_t len = ::boost::re_detail::distance(m_position, m_end);
489 len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
490 int val = m_traits.toi(m_position, m_position + len, 16);
497 put(static_cast<char_type>(val));
501 if(++m_position == m_end)
507 put(static_cast<char_type>(*m_position++ % 32));
510 put(static_cast<char_type>(27));
514 // see if we have a perl specific escape:
515 if((m_flags & boost::regex_constants::format_sed) == 0)
517 bool breakout = false;
522 m_restore_state = m_state;
523 m_state = output_next_lower;
528 m_state = output_lower;
533 m_restore_state = m_state;
534 m_state = output_next_upper;
539 m_state = output_upper;
544 m_state = output_copy;
551 // see if we have a \n sed style backreference:
552 int v = m_traits.toi(m_position, m_position+1, 10);
553 if((v > 0) || ((v == 0) && (m_flags & ::boost::regex_constants::format_sed)))
560 // octal ecape sequence:
562 std::ptrdiff_t len = ::boost::re_detail::distance(m_position, m_end);
563 len = (std::min)(static_cast<std::ptrdiff_t>(4), len);
564 v = m_traits.toi(m_position, m_position + len, 8);
565 BOOST_ASSERT(v >= 0);
566 put(static_cast<char_type>(v));
569 // Otherwise output the character "as is":
575 template <class OutputIterator, class Results, class traits>
576 void basic_regex_formatter<OutputIterator, Results, traits>::format_conditional()
578 if(m_position == m_end)
580 // oops trailing '?':
581 put(static_cast<char_type>('?'));
585 if(*m_position == '{')
587 const char_type* base = m_position;
589 v = m_traits.toi(m_position, m_end, 10);
592 // Try a named subexpression:
593 while((m_position != m_end) && (*m_position != '}'))
595 v = m_results.named_subexpression_index(base + 1, m_position);
597 if((v < 0) || (*m_position != '}'))
600 // oops trailing '?':
601 put(static_cast<char_type>('?'));
604 // Skip trailing '}':
609 std::ptrdiff_t len = ::boost::re_detail::distance(m_position, m_end);
610 len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
611 v = m_traits.toi(m_position, m_position + len, 10);
615 // oops not a number:
616 put(static_cast<char_type>('?'));
620 // output varies depending upon whether sub-expression v matched or not:
621 if(m_results[v].matched)
623 m_have_conditional = true;
625 m_have_conditional = false;
626 if((m_position != m_end) && (*m_position == static_cast<char_type>(':')))
630 // save output state, then turn it off:
631 output_state saved_state = m_state;
632 m_state = output_none;
633 // format the rest of this scope:
634 format_until_scope_end();
635 // restore output state:
636 m_state = saved_state;
641 // save output state, then turn it off:
642 output_state saved_state = m_state;
643 m_state = output_none;
644 // format until ':' or ')':
645 m_have_conditional = true;
647 m_have_conditional = false;
649 m_state = saved_state;
650 if((m_position != m_end) && (*m_position == static_cast<char_type>(':')))
654 // format the rest of this scope:
655 format_until_scope_end();
660 template <class OutputIterator, class Results, class traits>
661 void basic_regex_formatter<OutputIterator, Results, traits>::format_until_scope_end()
666 if((m_position == m_end) || (*m_position == static_cast<char_type>(')')))
669 }while(m_position != m_end);
672 template <class OutputIterator, class Results, class traits>
673 void basic_regex_formatter<OutputIterator, Results, traits>::put(char_type c)
675 // write a single character to output
676 // according to which case translation mode we are in:
677 switch(this->m_state)
681 case output_next_lower:
682 c = m_traits.tolower(c);
683 this->m_state = m_restore_state;
685 case output_next_upper:
686 c = m_traits.toupper(c);
687 this->m_state = m_restore_state;
690 c = m_traits.tolower(c);
693 c = m_traits.toupper(c);
702 template <class OutputIterator, class Results, class traits>
703 void basic_regex_formatter<OutputIterator, Results, traits>::put(const sub_match_type& sub)
705 typedef typename sub_match_type::iterator iterator_type;
706 iterator_type i = sub.first;
707 while(i != sub.second)
715 class string_out_iterator
716 #ifndef BOOST_NO_STD_ITERATOR
717 : public std::iterator<std::output_iterator_tag, typename S::value_type>
722 string_out_iterator(S& s) : out(&s) {}
723 string_out_iterator& operator++() { return *this; }
724 string_out_iterator& operator++(int) { return *this; }
725 string_out_iterator& operator*() { return *this; }
726 string_out_iterator& operator=(typename S::value_type v)
732 #ifdef BOOST_NO_STD_ITERATOR
733 typedef std::ptrdiff_t difference_type;
734 typedef typename S::value_type value_type;
735 typedef value_type* pointer;
736 typedef value_type& reference;
737 typedef std::output_iterator_tag iterator_category;
741 template <class OutputIterator, class Iterator, class Alloc, class charT, class traits>
742 OutputIterator regex_format_imp(OutputIterator out,
743 const match_results<Iterator, Alloc>& m,
744 const charT* p1, const charT* p2,
745 match_flag_type flags,
749 if(flags & regex_constants::format_literal)
751 return re_detail::copy(p1, p2, out);
754 re_detail::basic_regex_formatter<
756 match_results<Iterator, Alloc>,
757 traits > f(out, m, t);
758 return f.format(p1, p2, flags);
762 } // namespace re_detail
764 template <class OutputIterator, class Iterator, class charT>
765 OutputIterator regex_format(OutputIterator out,
766 const match_results<Iterator>& m,
768 match_flag_type flags = format_all
771 re_detail::trivial_format_traits<charT> traits;
772 return re_detail::regex_format_imp(out, m, fmt, fmt + traits.length(fmt), flags, traits);
775 template <class OutputIterator, class Iterator, class charT>
776 OutputIterator regex_format(OutputIterator out,
777 const match_results<Iterator>& m,
778 const std::basic_string<charT>& fmt,
779 match_flag_type flags = format_all
782 re_detail::trivial_format_traits<charT> traits;
783 return re_detail::regex_format_imp(out, m, fmt.data(), fmt.data() + fmt.size(), flags, traits);
786 template <class Iterator, class charT>
787 std::basic_string<charT> regex_format(const match_results<Iterator>& m,
789 match_flag_type flags = format_all)
791 std::basic_string<charT> result;
792 re_detail::string_out_iterator<std::basic_string<charT> > i(result);
793 re_detail::trivial_format_traits<charT> traits;
794 re_detail::regex_format_imp(i, m, fmt, fmt + traits.length(fmt), flags, traits);
798 template <class Iterator, class charT>
799 std::basic_string<charT> regex_format(const match_results<Iterator>& m,
800 const std::basic_string<charT>& fmt,
801 match_flag_type flags = format_all)
803 std::basic_string<charT> result;
804 re_detail::string_out_iterator<std::basic_string<charT> > i(result);
805 re_detail::trivial_format_traits<charT> traits;
806 re_detail::regex_format_imp(i, m, fmt.data(), fmt.data() + fmt.size(), flags, traits);
811 #pragma warning(push)
812 #pragma warning(disable: 4103)
814 #ifdef BOOST_HAS_ABI_HEADERS
815 # include BOOST_ABI_SUFFIX
823 #endif // BOOST_REGEX_FORMAT_HPP