• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

b1f6c1c4 / ProfessionalAccounting / 297

19 Feb 2023 04:15AM UTC coverage: 36.498% (+0.5%) from 35.998%
297

push

appveyor

b1f6c1c4
fix coupling bug

9985 of 27358 relevant lines covered (36.5%)

716.47 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

63.64
/AccountingServer.Shell/Util/ParseHelper.cs
1
/* Copyright (C) 2020-2023 b1f6c1c4
2
 *
3
 * This file is part of ProfessionalAccounting.
4
 *
5
 * ProfessionalAccounting is free software: you can redistribute it and/or
6
 * modify it under the terms of the GNU Affero General Public License as
7
 * published by the Free Software Foundation, version 3.
8
 *
9
 * ProfessionalAccounting is distributed in the hope that it will be useful, but
10
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License
12
 * for more details.
13
 *
14
 * You should have received a copy of the GNU Affero General Public License
15
 * along with ProfessionalAccounting.  If not, see
16
 * <https://www.gnu.org/licenses/>.
17
 */
18

19
using System;
20
using System.Collections.Generic;
21
using System.Diagnostics.CodeAnalysis;
22
using System.Text.RegularExpressions;
23
using System.Threading.Tasks;
24
using AccountingServer.BLL;
25
using AccountingServer.BLL.Parsing;
26
using AccountingServer.BLL.Util;
27
using AccountingServer.Entities;
28

29
namespace AccountingServer.Shell.Util;
30

31
/// <summary>
32
///     扩展的字符串匹配
33
/// </summary>
34
[SuppressMessage("ReSharper", "UnusedParameter.Global")]
35
public static class ParseHelper
36
{
37
    /// <summary>
38
    ///     匹配EOF
39
    /// </summary>
40
    /// <param name="facade">占位符</param>
41
    /// <param name="expr">表达式</param>
42
    // ReSharper disable once UnusedParameter.Global
43
    public static void Eof(this FacadeBase facade, string expr)
44
    {
142✔
45
        if (!string.IsNullOrWhiteSpace(expr))
142✔
46
            throw new ArgumentException("语法错误", nameof(expr));
2✔
47
    }
140✔
48

49
    public static IAsyncEnumerable<Voucher> RunVoucherQueryAsync(this Accountant acc, string str)
50
    {
×
51
        var res = FacadeF.ParsingF.VoucherQuery(ref str, acc.Client);
×
52
        FacadeF.ParsingF.Eof(str);
×
53
        return acc.SelectVouchersAsync(res);
×
54
    }
×
55

56
    public static ValueTask<long> DeleteVouchersAsync(this Accountant acc, string str)
57
    {
×
58
        var res = FacadeF.ParsingF.VoucherQuery(ref str, acc.Client);
×
59
        FacadeF.ParsingF.Eof(str);
×
60
        return acc.DeleteVouchersAsync(res);
×
61
    }
×
62

63
    public static ValueTask<ISubtotalResult> RunGroupedQueryAsync(this Accountant acc, string str)
64
    {
×
65
        var res = FacadeF.ParsingF.GroupedQuery(ref str, acc.Client);
×
66
        FacadeF.ParsingF.Eof(str);
×
67
        return acc.SelectVoucherDetailsGroupedAsync(res);
×
68
    }
×
69

70
    public static ValueTask<ISubtotalResult> RunVoucherGroupedQueryAsync(this Accountant acc, string str)
71
    {
×
72
        var res = FacadeF.ParsingF.VoucherGroupedQuery(ref str, acc.Client);
×
73
        FacadeF.ParsingF.Eof(str);
×
74
        return acc.SelectVouchersGroupedAsync(res);
×
75
    }
×
76

77
    /// <summary>
78
    ///     忽略空白和注释
79
    /// </summary>
80
    /// <param name="facade">占位符</param>
81
    /// <param name="expr">表达式</param>
82
    public static void TrimStartComment(this FacadeBase facade, ref string expr)
83
    {
915✔
84
        expr = expr.TrimStart();
915✔
85
        var regex = new Regex(@"[^\r\n]*(\r\n|\n|\n\r)");
915✔
86
        while (expr.Length > 2 &&
984✔
87
               expr[0] == '/' &&
88
               expr[1] == '/')
89
        {
69✔
90
            var m = regex.Match(expr);
69✔
91
            if (!m.Success)
69✔
92
            {
×
93
                expr = string.Empty;
×
94
                return;
×
95
            }
96

97
            expr = expr[m.Length..];
69✔
98
            expr = expr.TrimStart();
69✔
99
        }
69✔
100
    }
915✔
101

102
    /// <summary>
103
    ///     匹配行
104
    /// </summary>
105
    /// <param name="facade">占位符</param>
106
    /// <param name="expr">表达式</param>
107
    /// <returns>字符串</returns>
108
    public static string Line(this FacadeBase facade, ref string expr)
109
    {
×
110
        var id = expr.IndexOf('\n');
×
111
        if (id < 0)
×
112
        {
×
113
            var tmp = expr;
×
114
            expr = null;
×
115
            return tmp;
×
116
        }
117

118
        var line = expr[..id];
×
119
        expr = expr[(id + 1)..];
×
120
        return line;
×
121
    }
×
122

123
    /// <summary>
124
    ///     匹配带括号和连续字符串
125
    /// </summary>
126
    /// <param name="facade">占位符</param>
127
    /// <param name="expr">表达式</param>
128
    /// <param name="allow">允许括号</param>
129
    /// <param name="predicate">是否有效</param>
130
    /// <returns>字符串</returns>
131
    public static string Token(this FacadeBase facade, ref string expr, bool allow = true,
132
        Func<string, bool> predicate = null)
133
    {
907✔
134
        expr = expr.TrimStart();
907✔
135
        if (expr.Length == 0)
907✔
136
            return null;
12✔
137

138
        if (allow)
895✔
139
            if (expr[0] == '\'' ||
108✔
140
                expr[0] == '"')
141
            {
76✔
142
                var tmp = expr;
76✔
143
                var res = facade.Quoted(ref expr);
76✔
144
                if (!predicate?.Invoke(res) != true)
76✔
145
                    return res;
75✔
146

147
                expr = tmp;
1✔
148
                return null;
1✔
149
            }
150

151
        var id = 1;
819✔
152
        while (id < expr.Length)
2,866✔
153
        {
2,716✔
154
            if (char.IsWhiteSpace(expr[id]))
2,716✔
155
                break;
669✔
156

157
            id++;
2,047✔
158
        }
2,047✔
159

160
        var t = expr[..id];
819✔
161
        if (!predicate?.Invoke(t) == true)
819✔
162
            return null;
466✔
163

164
        expr = expr[id..];
353✔
165
        return t;
353✔
166
    }
907✔
167

168
    /// <summary>
169
    ///     匹配可选的数
170
    /// </summary>
171
    /// <param name="facade">占位符</param>
172
    /// <param name="expr">表达式</param>
173
    /// <returns>数</returns>
174
    public static double? Double(this FacadeBase facade, ref string expr)
175
    {
181✔
176
        var d = double.NaN;
181✔
177
        if (facade.Token(ref expr, false, t => double.TryParse(t, out d)) != null)
181✔
178
            return d;
75✔
179

180
        return null;
106✔
181
    }
181✔
182

183
    /// <summary>
184
    ///     匹配数
185
    /// </summary>
186
    /// <param name="facade">占位符</param>
187
    /// <param name="expr">表达式</param>
188
    /// <returns>数</returns>
189
    public static double DoubleF(this FacadeBase facade, ref string expr) => Double(facade, ref expr) ??
5✔
190
        throw new FormatException();
191

192
    /// <summary>
193
    ///     匹配可选的非零长度字符串
194
    /// </summary>
195
    /// <param name="facade">占位符</param>
196
    /// <param name="expr">表达式</param>
197
    /// <param name="opt">字符串</param>
198
    /// <returns>是否匹配</returns>
199
    public static bool Optional(this FacadeBase facade, ref string expr, string opt)
200
    {
323✔
201
        expr = expr.TrimStart();
323✔
202
        if (!expr.StartsWith(opt, StringComparison.Ordinal))
323✔
203
            return false;
261✔
204

205
        expr = expr[opt.Length..];
62✔
206
        return true;
62✔
207
    }
323✔
208

209
    /// <summary>
210
    ///     匹配可选的非零长度字符串
211
    /// </summary>
212
    /// <param name="facade">占位符</param>
213
    /// <param name="expr">表达式</param>
214
    /// <param name="opts">字符串</param>
215
    /// <returns>是否匹配</returns>
216
    public static string Optional(this FacadeBase facade, ref string expr, params string[] opts)
217
    {
×
218
        expr = expr.TrimStart();
×
219
        foreach (var opt in opts)
×
220
            if (expr.StartsWith(opt, StringComparison.Ordinal))
×
221
            {
×
222
                expr = expr[opt.Length..];
×
223
                return opt;
×
224
            }
225

226
        return null;
×
227
    }
×
228

229
    /// <summary>
230
    ///     匹配带引号的字符串
231
    /// </summary>
232
    /// <param name="facade">占位符</param>
233
    /// <param name="expr">表达式</param>
234
    /// <param name="c">引号(若为空表示任意)</param>
235
    // ReSharper disable once UnusedParameter.Global
236
    public static string Quoted(this FacadeBase facade, ref string expr, char? c = null)
237
    {
179✔
238
        expr = expr.TrimStart();
179✔
239
        if (expr.Length < 1)
179✔
240
            return null;
7✔
241

242
        var ch = expr[0];
172✔
243
        if (c != null &&
172✔
244
            ch != c)
245
            return null;
71✔
246

247
        var id = -1;
101✔
248
        while (true)
164✔
249
        {
164✔
250
            id = expr.IndexOf(ch, id + 2);
164✔
251
            if (id < 0)
164✔
252
                throw new ArgumentException("语法错误", nameof(expr));
1✔
253

254
            if (id == expr.Length - 1)
163✔
255
                break;
2✔
256
            if (expr[id + 1] != ch)
161✔
257
                break;
98✔
258
        }
63✔
259

260
        var s = expr[..(id + 1)];
100✔
261
        expr = expr[(id + 1)..];
100✔
262
        return s.Dequotation();
100✔
263
    }
178✔
264

265
    /// <summary>
266
    ///     匹配可选的冒号开始的记账凭证检索式
267
    /// </summary>
268
    /// <param name="facade">占位符</param>
269
    /// <param name="expr">表达式</param>
270
    /// <param name="client">客户端</param>
271
    /// <returns>记账凭证检索式</returns>
272
    public static IQueryCompounded<IVoucherQueryAtom> OptColVouchers(this FacadeBase facade, ref string expr,
273
        Client client)
274
        => Optional(facade, ref expr, ":") ? facade.VoucherQuery(ref expr, client) : null;
×
275
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc