- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
MATLAB 中的许多函数(以及其他具有 c 派生的 scanf
/printf
的函数)用于写入或读取字符串(仅举几例: sscanf
、sprintf
、textscan
) 依赖于用户提供有效的 formatSpec
字符串,该字符串告诉函数结构要构建的字符串或要解析的字符串。我正在寻找一种方法来验证这样的 formatSpec
字符串,然后再使用它调用 sprintf
.
对于sprintf
,formatSpec
的结构描述为in the documentation并且如下:
我想特别指出formatSpec
的两个方面:
- (✓) A formatting operator starts with a percent sign,
%
, and ends with a conversion character.- (x)
formatSpec
can also include additional text before a percent sign,%
, or after a conversion character.
我考虑的解决方案涉及使用正则表达式来测试传入的字符串。到目前为止,我所拥有的是一个似乎能够匹配初始 %
和转换字符之间的所有内容的表达式,但不是“附加文本”可能会出现。
(%{1}(\d+\$)?[-+\s0#]*(\d+|\*)?(\.\d+)?[bt]?[diuoxXfeEgGcs]+)+
我还想添加捕获“除 %
、'
和 \
之外的任何可打印文本字符的功能,除非这些字符完全显示两次”。这需要在初始 %
之前和转换字符 之后捕获。
[ -~]
%
、'
和 \
:(?![\\%'] )
( §§§§ |'{2}|\\{2}|%{2})
(§ = 占位符) 我在使用“unless”时遇到问题,即获取否定前瞻以丢弃单次出现但允许两次出现指定字符。
formatSpec
字符串(即不使用正则表达式,或使用更好的方法)?消歧义:在 formatSpec
字符串的情况下,格式化运算符 的两边都有“自由文本”,文本应被视为 的一部分strong>下一个 格式化运算符,除非没有剩余。下面是一个 formatSpec
字符串应该如何使用正则表达式拆分
的示例(其中 |
是每个匹配项的第一个字符):
Color %s, number1 %d, number2 %05d, hex %#x, float %5.2f, unsigned value %u.
| | | | | | |
最佳答案
我在这上面花了一些时间,我想我已经接近了,所以我会在答案中写下我目前的进展。我相当肯定它仍然可以改进。
首先是代码,使用the nice example string by Ro Yo Mi :
% valid input
sample_good = 'Color %s, we are looking for %%02droids %% number1 %d, number2 %05d, hex %#x, float %5.2f, unsigned value %u.';
% invalid input: "%02 droids" has a single percent sign which is not part of an operator
sample_bad = 'Color %s, we are looking for %02 droids %% number1 %d, number2 %05d, hex %#x, float %5.2f, unsigned value %u.';
group_from = '(';
group_to = ')';
printable = '([ -$&-\[\]-~]|%%|\\\\)*';
atomic_op = '(?<!%)%(\d+\$)?[ +#-]*(\d+|\*)?(\.\d*)?[bt]?[diuoxXfeEgGcs]';
% pattern for full validation
full_patt = ['^' group_from printable atomic_op group_to '*' printable '$'];
% pattern for splitting valid strings
part_patt = [printable atomic_op];
% examples
matches_full_bad = regexp(sample_bad,full_patt); % no match
matches_full_good = regexp(sample_good,full_patt); % match
matches_parts_good = regexp(sample_good,part_patt,'match'); % sliced matches
第一个示例字符串是有效的,第二个字符串由于 %02 droids
是字符串的一部分而被破坏。我定义了一些辅助模式;请注意,其中大多数已经包含了组。 printable
模式使用除 %
和 \
外的所有 ASCII,加上 %%
和 \\
。请注意,为了匹配双反斜杠,我们需要在搜索表达式中使用四个反斜杠(两个转义反斜杠)。
我所说的 atomic_op
是一种匹配以百分号开头并以转换字符结尾的格式运算符的模式。它使用负向后视来避免匹配以 %%
开头的虚假格式运算符。由于懒惰,我采取了一些捷径(例如 te
在我的版本中有效)。对于不太邪恶的输入,它应该非常有用。
最重要的部分是full_patt
和part_patt
。前者尝试匹配完整的格式规范,以确定它是否有效。不幸的是,在嵌套组的情况下,MATLAB 仅存储最外层 级别的标记;在我们的例子中,这没有用。这就是 part_patt
发挥作用的地方:它只匹配“printable_string format_operator”。与 full_patt
一起使用,它可用于将您的完整字符串分割成有意义的贡献。请注意,part_patt
通常也会在其本地有效位置匹配无效字符串,因此两者确实必须一起使用。
考虑上面的具体例子:
>> matches_full_bad
matches_full_bad =
[]
>> matches_full_good
matches_full_good =
1
>> matches_parts_good{:}
ans =
Color %s
ans =
, we are looking for %%02droids %% number1 %d
ans =
, number2 %05d
ans =
, hex %#x
ans =
, float %5.2f
ans =
, unsigned value %u
让我们分析一下结果。 “坏”模式返回一个(虚假的)空向量,而“好”模式返回一个(真实的)1
作为完整模式。然后部分模式正确返回输入的每个相关子模式。但是请注意,结果中缺少句子末尾的最后一个句点,因为我们匹配了 printable atomic_op
block 。因为我们知道我们正在处理一个有效的字符串,所以字符串的其余部分(在最终匹配之后)应该分配给一个新的匹配,或者分配给最后一个匹配,这取决于您的偏好。
为清楚起见,以下是我想象的工作方式:
for sample={sample_bad,sample_good},
if regexp(sample{1},full_patt)
disp('Match found!');
matches = regexp(sample,part_patt,'match');
matches = matches{1}; % strip outermost singleton cell dimension
for k=1:length(matches)
fprintf('Format substring #%d: %s\n',k, matches{k});
end
%TODO: treat final printable part of the string
else
disp('Uh-oh, no match!')
end
end
关于regex - 如何在 MATLAB 中验证 formatSpec 字符串?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38169682/
我是一名优秀的程序员,十分优秀!