4

我有一个这样的文件:

This \word{is} some text.
This is some \word{more text}.
\word{This} is \word{yet} some more \word{text}.

我需要创建一个列表,其中包含出现在\word{和匹配的右大括号之间的所有文本},例如:

is
more text
This
yet
text
  • 左大括号和右大括号总是出现在同一行,从不跨越多行。
  • 文档中存在其他大括号,但没有出现在\word{}.

如何打印出现在中的所有文本的列表\word{}

4

10 回答 10

9

看来您正在处理一个 TeX 文件......那么为什么不直接使用 TeX 来执行此操作呢?那么你就确定不会有任何问题和副作用,例如,

\word {there's a space between \verb=\word= and the curly bracket}

这仍然有效!它仍然适用于多行内容:

\word{this is
    a multiline stuff \emph{and you can even add more groupings in it,}
    it'll still work fine!}

在您的 (La)TeX 序言中,只需添加:

\newwrite\file
\immediate\openout\file=output.txt

\def\word#1{\immediate\write\file{#1}}

或者\newcommand如果您使用的是 LaTeX 而不是plainTeX,请使用。

你也可以把你的定义宏放在\immediate\write\file{#1}里面。\word如果您无权访问\word宏(例如,它在类或样式文件中),您可以:

\let\oldword\word
\def\word#1{\immediate\write\file{#1}\oldword{#1}}

希望这可以帮助!

于 2013-07-11T10:52:06.410 回答
7

具有 PCRE 功能的 grep 将完成这项工作:

grep -Po "(?<=\\word{)[^}]*(?=})" file

现场演示:http: //ideone.com/uzEzBF

于 2013-07-07T06:56:32.230 回答
4

无需调用任何外部实用程序的纯

while read -r x; do
  while [[ $x =~ \\word{([^}]+)} ]]; do
    echo ${BASH_REMATCH[1]}
    x=${x#*$BASH_REMATCH}
  done
done <infile

输入文件:

$ cat infile
This \word{is} some text.
{This \word{is}}some text.
This is some \word{more text}.
\word{This} is \word{yet} some more \word{text}.

输出:

is
is
more text
This
yet
text

诀窍是在内置函数中-r设置的选项。这不会被视为读取行中的转义字符。然后在字符串中找到模式时循环。然后打印内部匹配的字符串,并切碎输入字符串。read \\word{...}

对于小文件(1-2 MB),我会使用这个版本,因为它使用的资源非常少。但是对于大文件,我建议使用anubhava - 解决方案,因为它读取文件的效率更高!

于 2013-07-11T10:39:04.457 回答
3

由于并非所有版本的 grep 都具有 PCRE,因此这是一个仅使用扩展正则表达式的解决方案。

grep -Eo "\\word{.+}" file_name | sed -e "s/\\word{//" -e "s/}//"

于 2013-07-07T07:13:57.177 回答
1

perl 也有帮助:

perl -nlE 'say "$_" for (m/\\word\{(.*?)\}/g);'  < tex.txt

对于这个输入:

This{ \word{is}} some text.
This is some \word{more text}.
This is {some \word{aaa text}} This is {some \word{bbb text} This is some \word{ccc text}} This is some {\word{ddd text}}
{\word{This} is \word{yet} some more \word{text}.}

印刷:

is
more text
aaa text
bbb text
ccc text
ddd text
This
yet
text
于 2013-07-17T18:00:35.323 回答
1
$ cat testfile
This \word{is} some text.
This is some \word{more text}.
\word{This} is \word{yet} some more \word{text}.

$ awk '$0 ~ /\\word{[^}]*}/ { nelts = split($0, arr, /\\word{/); for (i=1; i <= nelts; i++) if (arr[i] ~ /^[^}]*}/) print substr(arr[i], 1, index(arr[i], "}") - 1); }' testfile
is
more text
This
yet
text

如果碰巧有\word{\word{STRING}},STRING 会被打印出来。换句话说,它递归地工作。对不起,如果那不是你想要的。

于 2013-07-11T05:17:09.827 回答
1

GNU 的代码:

sed -nr ':b;s/(\\word\{[^}]+\})/\1\n/;s/.*\\word\{([^}]+)\}\n/\1\n/;T;P;D;tb' file

$猫文件
这 \word{是} 一些文本。
这是一些 \word{more text}。
\word{This} 是 \word{yet} 一些 \word{text}。
{\word{This} 是 \word{yet} {some} 更多 \word{text}。}

$ sed -nr ':b;s/(\\word\{[^}]+\})/\1\n/;s/.*\\word\{([^}]+)\}\ n/\1\n/;T;P;D;tb' 文件
是
更多文字
这个
然而
文本
这个
然而
文本
于 2013-07-16T08:15:07.520 回答
1

sed

sed 's/.*\\word{\([^}]*\)}.*/\1/g' input.txt

上面的表达式删除了除了括号内的所有内容。如果将来您需要跨多行匹配,awk可能会更容易:

awk -F "\\word{" 'BEGIN { RS = "}" } { print $2 }' input.txt

这设置\word{为字段分隔符和}记录分隔符,这意味着它$2指的是括号内的内容。

于 2013-07-17T21:38:59.067 回答
1

混合 grep 和 sed:

egrep -o '\\word\{[^\{\}]+\}' | sed 's/\\word{//;s/}//'

为了好玩,我还编了一个纯 bash 版本:

while read -r l
do
    n=${#l}
    ll="${l#*\\word{}"
    while [ $n -ne ${#ll} ]
    do
        echo "${ll%%\}*}"
        n=${#ll}
        ll="${ll#*\\word{}"
    done
done

不是很干净,但它适用于您的示例

于 2013-07-11T09:57:32.997 回答
1

awk 被发明来进行文本处理:

$ awk 'sub(/.*\\word{/,"")' RS='}' file
is
more text
This
yet
text
is

$ cat file
This \word{is} some text.
This is some \word{more text}.
\word{This} is \word{yet} some more \word{text}.
{ This \word{is} some text }
于 2013-07-17T04:04:40.923 回答