【问题标题】:Replace text in one line but avoid certain pattern替换一行中的文本但避免某些模式
【发布时间】:2018-02-14 03:59:11
【问题描述】:

我正在尝试使用 sed 替换一行中的文本,但前提是它不在特定模式内。 例如,该行可能是

bla blab blab \cite{bla} \cite[prout]{bla} \footcite[prout][hein]{ bla } Bla aBla

结果必须是(通过用不区分大小写的 KUI 替换 bla)

KUI blab blab \cite{bla} \cite[prout]{bla} \footcite[prout][hein]{ bla } KUI aBla

我不确定sed 是否是正确的命令。可以使用其他经典的 unix 命令。

【问题讨论】:

  • 我怀疑你可以用 sed 做任何有趣的事情,因为语言可以嵌套大括号。 (除非您计划使用一个只能用一半时间的糟糕解决方案)。使用 perl 命令行的解决方案是可能的。
  • @CasimiretHippolyte 你知道语法吗?
  • 你可以试试 Perl。 Like this.
  • @Guuk:该语言似乎使用了一种允许嵌套 tags 的 Latex 语法。
  • @CasimiretHippolyte 你是对的,但我的问题的目的是编写一个代码来自动为某些单词添加特定的乳胶命令,并避免在某些情况下应用它。在某些情况下,我想避免添加嵌套标签。

标签: regex string sed replace


【解决方案1】:

gawk 解决 1 级括号 {...}:

awk 'BEGIN{ IGNORECASE=1 }
     {   split($0, a, /\{[^{}]+\}/, seps); 
         for(i=1; i in a; i++) { 
             gsub(/\<bla\>/,"KUI",a[i]); 
             printf "%s%s",a[i],seps[i] 
         } 
         print ""  
     }' file

输出:

KUI blab blab \cite{bla} \cite[prout]{bla} \footcite[prout][hein]{ bla } KUI aBla

【讨论】:

    【解决方案2】:

    sed 用于简单的 s/old/new/,仅此而已。你不只是在做 s/old/new/ 所以你不应该考虑 sed。只需使用 awk:

    $ cat tst.awk
    function descend( internalStr) {
        while( ++i <= length($0) ) {
            char = substr($0,i,1)
            internalStr = internalStr char
            if (char == "{") {
                internalStr = internalStr descend()
            }
            else if (char == "}") {
                return internalStr
            }
        }
    }
    BEGIN { IGNORECASE=1 }
    {
        fullStr = externalStr = ""
        i = 0
        while( ++i <= length($0) ) {
            char = substr($0,i,1)
            externalStr = externalStr char
            if (char == "{") {
                gsub(/\<bla\>/,"KUI",externalStr)
                fullStr = fullStr externalStr descend()
                externalStr = ""
            }
        }
        gsub(/\<bla\>/,"KUI",externalStr)
        print fullStr externalStr
    }
    

    .

    $ cat file
    bla blab blab \cite{bla} \cite[prout]{bla} \footcite[prout][hein]{ bla } Bla aBla
    bla \tag1{ bla \tag2{ bla } bla } bla
    
    $ gawk -f tst.awk file
    KUI blab blab \cite{bla} \cite[prout]{bla} \footcite[prout][hein]{ bla } KUI aBla
    KUI \tag1{ bla \tag2{ bla } bla } KUI
    

    以上使用 GNU awk 作为单词边界和 IGNORECASE。使用其他 awk 可以轻松解决这些需求。

    请注意,它甚至适用于嵌套标签(第二输入/输出行)。

    【讨论】:

    【解决方案3】:

    做:

    sed -e 's/\<[bB]la\>/KUI/g' yourFile
    

    地点:

    \<bla\> 
    

    指定搜索与字符串 'bla' 完全匹配的单词。 \&lt; 用于指定单词的开头。在这种情况下,单词必须以 b 或 B 开头。\&gt; 指定单词的结尾。在这种情况下,它必须以 a 结尾。在'b'('B')和'a'之间,必须只有一个'l'。

    更新 我注意到 sed 不能很好地读取字符 '{' 和 '}' 所以它也考虑一个词 {bla} 并将其翻译成 {KUI}。 解决方法如下:

    sed -e 's/{/opened/g' yourFile > newFile
    sed -e 's/}/closed/g' newFile1 > yourFile
    
    sed -e 's/\<[bB]la\>/KUI/g' yourFile > newFile
    
    sed -e 's/opened/{/g' newFile > yourFile
    sed -e 's/closed/}/g' yourFile > newFile
    

    它不是那么优雅,但它确实有效。

    希望对你有帮助

    【讨论】:

    • 它不适用于 OSX 上的 sedGNU sed。该命令替换所有出现
    • 显然,如果您的文件中没有字符串“opened”和“closed”,它会起作用。无论如何,你可以选择每一个你想让它工作的字符串。
    【解决方案4】:

    第一个变体 - 使用嵌套大括号。

    awk -F '' '
        function buf_sub() {
            gsub(/\ybla\y/, "KUI", buffer);
            string = string buffer;
            buffer = "";
        }
        BEGIN {
            IGNORECASE = 1;
        }
        {
            string = "";
            buffer = "";
            for(i = 1; i <= NF; i++) {
                if(cnt) 
                    string = string $i; 
                 else 
                    buffer = buffer $i;
                
                if($i == "{") {
                    cnt++;
                    buf_sub();
                } 
                if($i == "}") 
                    cnt--;  
            }
            buf_sub();
            print string;
        }
    ' input.txt
    

    输入

    bla blab blab \cite{bla} \cite[prout]{bla} \footcite[prout][hein]{ bla } Bla aBla
    blab bla blab \cite{bla} \cite[prout]{bla} \footcite[prout][hein]{ bla } aBla Bla
    bla \tag1{ bla \tag2{ bla } bla } bla 
    

    输出

    KUI blab blab \cite{bla} \cite[prout]{bla} \footcite[prout][hein]{ bla } KUI aBla
    blab KUI blab \cite{bla} \cite[prout]{bla} \footcite[prout][hein]{ bla } aBla KUI
    KUI \tag1{ bla \tag2{ bla } bla } KUI
    

    第二个变体 - 不处理大括号嵌套。

    sed -r 's/(\\[^}]*})/\n@#\1\n@#/g' input.txt |
    sed '/\\/! s/\bbla\b/KUI/gI;' |
    sed ':lab; N; $!b lab; s/\n@#//g;'
    

    输入

    bla blab blab \cite{bla} \cite[prout]{bla} \footcite[prout][hein]{ bla } Bla aBla
    blab bla blab \cite{bla} \cite[prout]{bla} \footcite[prout][hein]{ bla } aBla Bla
    

    输出

    KUI blab blab \cite{bla} \cite[prout]{bla} \footcite[prout][hein]{ bla } KUI aBla
    blab KUI blab \cite{bla} \cite[prout]{bla} \footcite[prout][hein]{ bla } aBla KUI
    

    【讨论】:

      【解决方案5】:

      使用 perl 的解决方案:

      perl -lpe 's/(\\footcite([^}]*)|\\cite([^}]*))(*SKIP)(*FAIL)|\bbla\b/KUI/ig' file
      

      在替换过程中将避免\footcite\cite命令。

      【讨论】:

      • 此解决方案基于@CasimiretHippolyte 命题。
      猜你喜欢
      • 1970-01-01
      • 2016-11-16
      • 1970-01-01
      • 2013-12-13
      • 1970-01-01
      • 2018-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多