OSDN Git Service

refactor
[winmerge-jp/winmerge-jp.git] / Src / SubstitutionList.cpp
1 /** 
2  * @file  SubstitutionList.cpp
3  *
4  * @brief Implementation file for SubstitutionList.
5  */
6
7 #include "pch.h"
8 #include "SubstitutionList.h"
9 #include <vector>
10 #include <Poco/RegularExpression.h>
11 #include "unicoder.h"
12
13 static std::string replaceEscapeSequences(const std::string& input)
14 {
15         std::string result;
16
17         for (size_t i = 0; i < input.size(); ++i)
18         {
19                 if (input[i] == '\\')
20                 {
21                         if (i + 1 < input.size())
22                         {
23                                 switch (input[i + 1])
24                                 {
25                                 case 'a':
26                                         result += '\a';
27                                         break;
28                                 case 'b':
29                                         result += '\b';
30                                         break;
31                                 case 'f':
32                                         result += '\f';
33                                         break;
34                                 case 'n':
35                                         result += '\n';
36                                         break;
37                                 case 'r':
38                                         result += '\r';
39                                         break;
40                                 case 't':
41                                         result += '\t';
42                                         break;
43                                 case 'v':
44                                         result += '\v';
45                                         break;
46                                 case 'x':
47                                         if (i + 3 < input.size())
48                                         {
49                                                 std::string hexValue = input.substr(i + 2, 2);
50                                                 try {
51                                                         unsigned int intValue = std::stoul(hexValue, nullptr, 16);
52                                                         result += static_cast<char>(intValue);
53                                                         i += 2;
54                                                 }
55                                                 catch (const std::invalid_argument&) {
56                                                         result += "\\x";
57                                                 }
58                                         }
59                                         else
60                                         {
61                                                 result += "\\x";
62                                         }
63                                         break;
64                                 default:
65                                         if (isdigit(input[i + 1]))
66                                                 result += '$';
67                                         result += input[i + 1];
68                                         break;
69                                 }
70                                 ++i;
71                         }
72                 }
73                 else
74                 {
75                         result += input[i];
76                 }
77         }
78
79         return result;
80 }
81
82 SubstitutionItem::SubstitutionItem(const std::string& pattern,
83         const std::string& replacement, int regexpCompileOptions)
84         : pattern(pattern)
85         , replacement(replaceEscapeSequences(replacement))
86         , regexpCompileOptions(regexpCompileOptions)
87         , regexp(pattern, regexpCompileOptions)
88 {
89 }
90
91 SubstitutionItem::SubstitutionItem(const SubstitutionItem& other)
92         : pattern(other.pattern)
93         , replacement(other.replacement)
94         , regexpCompileOptions(other.regexpCompileOptions)
95         , regexp(other.pattern, other.regexpCompileOptions)
96 {
97 }
98
99 void SubstitutionList::Add(const std::string& pattern, const std::string& replacement, int regexpCompileOptions)
100 {
101         m_list.emplace_back(pattern, replacement, regexpCompileOptions);
102 }
103
104 void SubstitutionList::Add(
105         const std::string& pattern, const std::string& replacement,
106         bool caseSensitive, bool matchWholeWordOnly)
107 {
108         int regexpCompileOptions = 
109                 caseSensitive ? 0 : Poco::RegularExpression::RE_CASELESS;
110         std::string rePattern;
111         for (auto c: pattern)
112         {
113                 switch (c)
114                 {
115                 case '\\': case '.': case '^': case '$': case '|':
116                 case '[':  case ']': case '(': case ')': case '!':
117                 case '?': case '*':  case '+': case '{': case '}':
118                         rePattern.push_back('\\');
119                         break;
120                 default:
121                         break;
122                 }
123                 rePattern.push_back(c);
124         }
125         if (matchWholeWordOnly)
126                 rePattern = "\\b" + rePattern + "\\b";
127         m_list.emplace_back(rePattern, replacement, regexpCompileOptions);
128 }
129
130 std::string SubstitutionList::Subst(const std::string& subject, int codepage/*=CP_UTF8*/) const
131 {
132         std::string replaced;
133
134         if (codepage != ucr::CP_UTF_8)
135         {
136                 // convert string into UTF-8
137                 ucr::buffer buf(subject.length() * 2);
138
139                 ucr::convert(ucr::NONE, codepage, reinterpret_cast<const unsigned char*>(subject.c_str()),
140                         subject.length(), ucr::UTF8, ucr::CP_UTF_8, &buf);
141
142                 replaced.assign(reinterpret_cast<const char *>(buf.ptr), buf.size);
143         }
144         else
145         {
146                 replaced = subject;
147         }
148
149         for (const auto& item : m_list)
150         {
151                 try
152                 {
153                         item.regexp.subst(replaced, item.replacement, Poco::RegularExpression::RE_GLOBAL);
154                 }
155                 catch (...)
156                 {
157                         // TODO:
158                 }
159         }
160
161         return replaced;
162 }
163
164 void SubstitutionList::RemoveAllFilters()
165 {
166         m_list.clear();
167 }
168