\mathbb{P}
在很长的现有文件中自动替换概率测度的分隔符的最佳策略是什么。
假设现有的 LaTeX 文件使用像\mathbb{P}(A)
、\mathbb{P}(B)
和 这样的符号\mathbb{P}(...)
,但它应该使用符号\mathbb{P}\lbrack ...\rbrack
。
我猜很多 LaTeX 用户都面临着这类问题,但也许可以在 LaTeX 之外更好地解决它——也许通过在代码编辑器中使用正则表达式?(我对正则表达式的经验很少。)
重要的是,并非所有圆括号都应被替换。只有紧随其后的左括号\mathbb{P}
和其对应的右括号才应被替换为方括号。
如果间隔的概率能够起作用,那就太好了 - 例如\mathbb{P}(\lbrack a, b))
,\mathbb{P}\lbrack\lbrack a, b)\rbrack
但如果有百分之一的替换是错误的,它仍然会有所帮助。
PS:当然,最好首先定义一个命令,比如\newcommand{\PP}[1]{\mathbb{P}\left\lbrack{#1}\right\rbrack}
,但我正在谈论一个\mathbb{P}(...)
在文本中硬编码的现有文档。
备注MWE
:
\documentclass{article}
\usepackage{amssymb}
\begin{document}
Basic examples: $\mathbb{P}(A)$,
nested: $\mathbb{P}(A\cup(A\cap B))$, intervall-notation: $\mathbb{P}(X\in[a,b))$,
left/right: $\mathbb{P}\left(X\in\left[a,(-b)^k\right)\right)$
$\mathbb{P} ... (these\ parenthesis\ should\ not\ be\ affacted)$.%because they are not directly after P.
Often $($ and $]$ are matched---e.g.:
$\mathbb{P}(X\in[a,\infty))$,
$\mathbb{P}\left( Y\in[b,c)\cup[d,e)\right)$ and often $[$ and $)$ are matched---e.g.:
$\mathbb{P}\left( Y\in[b,c)\cup(d,e]\right)$
Sometimes \texttt{left} and \texttt{right} are used and sometimes not. %\left and \right
And nesting can be quite deep.
\[\mathbb{P}\left( X\in \left( [a,b)\cup\left(c,3\left(a+(-1)^k(d+e)\right)\right] \right)\setminus (B\cap ( \lbrack k,k+1) \cup C )) \right)\]
There could be comments involved too:
\[\mathbb{P}( X\in \left( [a,b)\cup\left(c,3\left(a+(-1)(d+e)\right)\right] \right)\setminus (B\cap ( \lbrack k,k+1)%k+2)
\cup C )) )\]
\end{document}
答案1
一个简单的搜索/替换就是用 替换\mathbb{P}(
。\PP{P}(
然后,假设所有\mathbb{P}
都是以下形式,则\mathbb{P}(...)
应该有效:
如果 中的内容()
也有圆括号,则需要{}
在其周围添加一个额外的 。也就是说,像 这样的内容\PP{P}({AB))
需要更改为\PP{P}({(AB)})
。
\documentclass{article}
\usepackage{amssymb}
\newcommand*{\PP}{}% Ensure we are not overwriting an existing macro
\def\PP#1(#2){\mathbb{#1}[#2]}
\begin{document}
%$\mathbb{P}(A)$% Replaced "\mathbb{P}" with "\PP{P}"
$\PP{P}(A)$
\end{document}
答案2
只有紧接着的左括号
\mathbb{P}
和其对应的右括号应该被方括号替换。
这是一个基于 LuaLaTeX 的解决方案。它由 (a) 一个 Lua 函数组成,paren2brack
该函数使用 Lua 的强大string.gsub
功能;(b) 两个 LaTeX 实用宏(称为\ParenBrackOn
和\ParenBrackOff
),用于打开和关闭 Lua 函数。括号到方括号的替换是“即时”执行的,即 tex 文件本身不会被编辑或修改。
该解决方案不仅可以处理\mathbb{P}
;事实上,的参数\mathbb
可以是任何大写字母。
附录:我在 Lua 函数中添加了第二个string.gsub
操作,以便它可以处理诸如此类的情况\mathbb{P}\left(A\right)
。
% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{amssymb} % for '\mathbb' macro
\usepackage{luacode} % for 'luacode' env.
\begin{luacode}
function paren2brack ( s )
s = s:gsub( "(\\mathbb{%u})(%b())" , function ( x , y )
return x .. "[" .. y:sub(2,-2) .. "]"
end )
s = s:gsub( "(\\mathbb{%u})\\left%((.-)\\right%)" , function ( x , y )
return x .. "\\left[" .. y .. "\\right]"
end )
return s
end
\end{luacode}
%% Define a couple of LaTeX utility macros:
\newcommand\ParenBrackOn{\directlua{luatexbase.add_to_callback (
"process_input_buffer" , paren2brack , "paren2brack" )}}
\newcommand\ParenBrackOff{\directlua{luatexbase.remove_from_callback (
"process_input_buffer" , "paren2brack" )}}
\begin{document}
$\mathbb{P}(A)$, $\mathbb{Q}(B\cup(C\cap D))$, $\mathbb{P}\left(E\right)$
--- Lua function not activated
\ParenBrackOn % assign the Lua function to LuaTeX's 'process_input_buffer' callback
$\mathbb{P}(A)$, $\mathbb{Q}(B\cup(C\cap D))$, $\mathbb{P}\left(E\right)$
--- Lua function is activated
\end{document}
答案3
匹配嵌套的括号/方括号并不是一件容易的事;我建议使用以下正则表达式插入perl
vialatexindent
及其 yaml 接口。没有什么可以阻止您将其合并到您自己的perl
脚本中。
我用来生成输出的命令是
latexindent -rr -l=jakob.yaml myfile.tex -o=output.tex
输出.tex
\documentclass{article}
\usepackage{amssymb}
\begin{document}
Basic examples: $\mathbb{P}\left\lbrack A\right\rbrack$,
nested: $\mathbb{P}\left\lbrack A\cup(A\cap B)\right\rbrack$, intervall-notation: $\mathbb{P}\left\lbrack X\in[a,b)\right\rbrack$,
left/right: $\mathbb{P}\left\lbrack X\in\left[a,(-b)^k\right)\right\rbrack$
$\mathbb{P} ... (these\ parenthesis\ should\ not\ be\ affacted)$.%because they are not directly after P.
Often $($ and $]$ are matched---e.g.:
$\mathbb{P}\left\lbrack X\in[a,\infty)\right\rbrack$,
$\mathbb{P}\left\lbrack Y\in[b,c)\cup[d,e)\right\rbrack$ and often $[$ and $)$ are matched---e.g.:
$\mathbb{P}\left\lbrack Y\in[b,c)\cup(d,e]\right\rbrack$
Sometimes \texttt{left} and \texttt{right} are used and sometimes not. %\left and \right
And nesting can be quite deep.
\[\mathbb{P}\left\lbrack X\in \left( [a,b)\cup\left(c,3\left(a+(-1)^k(d+e)\right)\right] \right)\setminus (B\cap ( \lbrack k,k+1) \cup C )) \right\rbrack\]
There could be comments involved too:
\[\mathbb{P}\left\lbrack X\in \left( [a,b)\cup\left(c,3\left(a+(-1)(d+e)\right)\right] \right)\setminus (B\cap ( \lbrack k,k+1)%k+2)
\cup C )\right\rbrack )\]
\end{document}
以下jakob.yaml
是该方法的摘要:
为每个
$...$
并\[...\]
处理主体,查找并存储除最外层出现的、 、 、 、\left(...\right]
之外(...]
的\left[...\right)
所有[...)
内容\left(...\right)
(...)
最外层的出现
\left(...\right)
并(...)
替换为\left\lbrack...\right\rbrack
看看你的想法。毫无疑问,其他人可以做得更有效率。
jakob.yaml
replacements:
-
substitution: |-
s/((?<!\\)\$|\\\[) # opening between either $ or \[
(.*?) # body between $...$ or \[...\]
((?<!\\)\$|\\\])/ # closing $ or \]
my $begin = $1;
my $body = $2;
my $end = $3;
# operate on the body, only if it contains \mathbb
if($body =~ m|\\mathbb|){
my $storageToken = "jakob-paren-token";
my $storageCount = 0;
my @storageArray = ();
# \left(...\right]
# \left(...\right]
# \left(...\right]
my $leftRightRegEx =
qr|(
\\left\( # \left(
(?:
(?!
(?:\\left\() # anything except \left(
).
)*?
\\right\] # up to \right]
)|xs;
while( $body =~ m|$leftRightRegEx|xs ){
$storageCount++;
$body =~ s|$leftRightRegEx|
push(@storageArray,{id=>$storageToken.$storageCount,value=>$1});
$storageToken.$storageCount;|xse;
}
# (a,b]
# (a,b]
# (a,b]
my $intervalRegEx =
qr|(
\( # (
(?:
(?!
(?<!\\)\( # anything except (
).
)*?
(?<!\\)
\] # up to ]
)|xs;
while( $body =~ m|$intervalRegEx|xs ){
$storageCount++;
$body =~ s|$intervalRegEx|
push(@storageArray,{id=>$storageToken.$storageCount,value=>$1});
$storageToken.$storageCount;|xse;
}
# \left[...\right)
# \left[...\right)
# \left[...\right)
$leftRightRegEx =
qr|(
\\left\[ # \left[
(?:
(?!
(?:\\left\[) # anything except \left[
).
)*?
\\right\) # up to \right)
)|xs;
while( $body =~ m|$leftRightRegEx|xs ){
$storageCount++;
$body =~ s|$leftRightRegEx|
push(@storageArray,{id=>$storageToken.$storageCount,value=>$1});
$storageToken.$storageCount;|xse;
}
# [a,b)
# [a,b)
# [a,b)
$intervalRegEx =
qr|(
\[ # [
(?:
(?!
(?<!\\)\[ # anything except [
).
)*?
(?<!\\)
\) # up to )
)|xs;
while( $body =~ m|$intervalRegEx|xs ){
$storageCount++;
$body =~ s|$intervalRegEx|
push(@storageArray,{id=>$storageToken.$storageCount,value=>$1});
$storageToken.$storageCount;|xse;
}
# \left(...\right)
# \left(...\right)
# \left(...\right)
my $untilNoNestedLeftRightRegEx = qr|\\left\(
(?:
(?!
(?<!\\right\))
).
)*?
(?<!\\)
\\left\(|xs;
$leftRightRegEx =
qr|(
\\left\( # \left(
(?:
(?!
(?:\\left\() # anything except \left(
).
)*?
\\right\) # up to \right)
)|xs;
while( $body =~ m|$untilNoNestedLeftRightRegEx|xs ){
$storageCount++;
$body =~ s|$leftRightRegEx|
push(@storageArray,{id=>$storageToken.$storageCount,value=>$1});
$storageToken.$storageCount;|xse;
}
# now store all matched (...)
my $untilNoNestedParenRegEx = qr|\(
(?:
(?!
(?<!\\)\)
).
)*?
(?<!\\)
\(|xs;
my $parenRegEx = qr|(
\(
(?:
(?!
(?<!\\)\(
).
)*?
(?<!\\)
\))|xs;
while( $body =~ m|$untilNoNestedParenRegEx|){
$storageCount++;
$body =~ s|$parenRegEx|
push(@storageArray,{id=>$storageToken.$storageCount,value=>$1});
$storageToken.$storageCount;|xse;
}
# now make the substitution:
# \mathbb{(.*?)}\( (.*?) \)
# into
# \mathbb{$1}\lbrack $2 \rbrack
$body =~ s|(\\mathbb\{.*?\})\h*\((.*?)\)|$1\\left\\lbrack $2\\right\\rbrack|sg;
$body =~ s|(\\mathbb\{.*?\})\h*\\left\((.*?)\\right\)|$1\\left\\lbrack $2\\right\\rbrack|sg;
# finally, put the nested braces/intervals
# back in to the body
while(@storageArray){
my $entry = pop(@storageArray);
$body =~ s|${$entry}{id}|${$entry}{value}|s;
}
}
$begin.$body.$end;/sgxe