Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Regex 将特定单词后的行连接到另一个特定单词_Regex_Join_Vim - Fatal编程技术网

Regex 将特定单词后的行连接到另一个特定单词

Regex 将特定单词后的行连接到另一个特定单词,regex,join,vim,Regex,Join,Vim,我有一个.txt文件的成绩单,看起来像这样 MICHEAL: blablablabla. further talk by Michael. more talk by Michael. VALERIE: blublublublu. Valerie talks more. MICHAEL: blibliblibli. Michael talks again. ........ 总而言之,这种模式最多可使用4000行,不只是两个扬声器,而是多达七个不同的扬声器,所有扬声器都具有用大写字

我有一个.txt文件的成绩单,看起来像这样

MICHEAL: blablablabla.

further talk by Michael.

more talk by Michael.

VALERIE: blublublublu.

Valerie talks more.

MICHAEL: blibliblibli.

Michael talks again.

........
总而言之,这种模式最多可使用4000行,不只是两个扬声器,而是多达七个不同的扬声器,所有扬声器都具有用大写字母书写的唯一名称(如上面的示例所示)。 对于一些文本挖掘,我需要按照以下方式重新排列这个.txt文件

  • 将一位演讲者后面的几行连接起来,但仅限于仍然属于他的几行,以便上面的文件如下所示:

    MICHAEL: blablablabla. further talk by Michael. more talk by Michael.
    
    VALERIE: blublublublu. Valerie talks more.
    
    MICHAEL: blibliblibli. Michael talks again.
    
  • 按字母顺序对.txt文件中现在正确连接的行进行排序,以便演讲者所说的所有行现在都在一起。但是,sort函数不应该对一个说话人所说的句子进行排序(在将每个说话人的行排序在一起之后)

  • 我知道一些基本的vim命令,但还不足以解决这个问题。特别是第一个。我不知道我可以在vim中实现什么样的模式,这样它只连接每个扬声器的线路


    任何帮助都会被极大地吸引

    在vim中,您可以采取两步方法,首先替换所有换行符

    :%s/\n\+/ /g
    
    然后在术语
    大写:
    前插入新行,第一行除外:

    :%s/ \([[:upper:]]\+:\)/\r\1/g
    
    对于排序,您可以利用UNIX排序程序:

    :%sort!
    
    可以使用管道符号将它们组合在一起:

    :%s/\n\+/ /g | %s/ \([[:upper:]]\+:\)/\r\1/g | %!sort
    
    并将它们映射到vimrc文件中的密钥:

    :nnoremap <F5> :%s/\n\+/ /g \| %s/ \([[:upper:]]\+:\)/\r\1/g \| %sort! <CR>
    
    :nnoremap:%s/\n\+//g\\\\%s/\([[:upper:]\+:\)/\r\1/g\\\\\\\%sort!
    

    如果在正常模式下按F5,则会发生转换。请注意,
    |
    需要在
    nnoremap
    命令中进行转义。

    我对
    vim
    了解不多,但我正要匹配与特定扬声器对应的行,下面是实现这一点的方法

    正则表达式:
    /([A-Z]+:)([A-Za-Z\s\.]+)(?!\1)$/gm


    说明:
    ([A-Z]+:)
    捕获只包含大写字母的说话人姓名

    ([A-Za-z\s\.]+)
    捕获对话。

    (?!\1)$
    反向引用演讲者的姓名,并比较下一个演讲者是否与上一个演讲者相同。如果不匹配,则匹配直到找到新的扬声器


    我希望这至少能帮助您进行匹配。

    好的,首先回答:

    :g/^\u\+:/,/\n\u\+:\|\%$/join
    
    现在解释一下:

    • g代表全局,并在匹配的每一行上执行以下命令
    • /^\u+:/是模式:g搜索:^是行的开头,\u是大写字符,+表示一个或多个匹配项,是:
    • 然后是棘手的一点,我们将执行的命令设置为一个范围,从匹配到其他模式匹配/\n\u+:\\\%$是由管道分隔的两部分\n\u+:是一个新行,后跟最后一个模式,即下一个发言者前面的行\%%$是文件的结尾
    • join照罐头上写的做
    因此,把它放在一起:对于每个发言者,加入到下一个发言者之前的一行或文件末尾

    最接近我现在的排序是

    :排序/\u+:/r


    这将只按说话人姓名排序,并反转另一行,因此它不是您真正想要的

    以下是解决您问题的脚本解决方案

    它没有经过很好的测试,所以我添加了一些注释,以便您可以轻松地修复它

    要使其运行,只需执行以下操作:

    • 在脚本顶部的
      g:speakers
      var中填入所需的大写名称
    • 脚本的源代码(例如:sav/tmp/script.vim | so%)
    • 运行
      :调用JoinAllSpeakLines()
      通过扬声器连接线路
    • 运行
      :调用SortSpeakLines()
      进行排序
    您可以调整不同的模式以更好地满足您的需要,例如添加一些空间容差(
    \u\{2,}\s*\ze:

    代码如下:

    " Fill the following array with all the speakers names:
    let g:speakers = [ 'MICHAEL', 'VALERIE', 'MATHIEU' ]
    call sort(g:speakers)
    
    
    function! JoinAllSpeakLines()
    " In the whole file, join all the lines between two uppercase speaker names 
    " followed by ':', first inclusive:
        silent g/\u\{2,}:/call JoinSpeakLines__()
    endf
    
    function! SortSpeakLines()
    " Sort the whole file by speaker, keeping the order for
    " each speaker.
    " Must be called after JoinAllSpeakLines().
    
        " Create a new dict, with one key for each speaker:
        let speakerlines = {}
        for speaker in g:speakers
            let speakerlines[speaker] = []
        endfor
    
        " For each line in the file:
        for line in getline(1,'$')
            let speaker = GetSpeaker__(line)
            if speaker == ''
                continue
            endif
            " Add the line to the right speaker:
            call add(speakerlines[speaker], line)
        endfor
    
        " Delete everything in the current buffer:
        normal gg"_dG
    
        " Add the sorted lines, speaker by speaker:
        for speaker in g:speakers
            call append(line('$'), speakerlines[speaker])
        endfor
    
        " Delete the first (empty) line in the buffer:
        normal gg"_dd
    endf
    
    function! GetOtherSpeakerPattern__(speaker)
    " Returns a pattern which matches all speaker names, except the
    " one given as a parameter.
        " Create an new list with a:speaker removed:
        let others = copy(g:speakers)
        let idx = index(others, a:speaker)
        if idx != -1
            call remove(others, idx)
        endif
        " Create and return the pattern list, which looks like
        " this : "\v<MICHAEL>|<VALERIE>..."
        call map(others, 'printf("<%s>:",v:val)')
        return '\v' . join(others, '|')
    endf
    
    function! GetSpeaker__(line)
    " Returns the uppercase name followed by a ':' in a line
        return matchstr(a:line, '\u\{2,}\ze:')
    endf
    
    function! JoinSpeakLines__()
    " When cursor is on a line with an uppercase name, join all the
    " following lines until another uppercase name.
        let speaker = GetSpeaker__(getline('.'))
        if speaker == ''
            return
        endif
        normal V
        " Search for other names after the cursor line:
        let srch = search(GetOtherSpeakerPattern__(speaker), 'W')
        echo srch
        if srch == 0
            " For the last one only:
            normal GJ
        else
            normal kJ
        endif
    endf
    
    “用所有扬声器名称填充以下数组:
    让g:演讲者=[‘迈克尔’、‘瓦莱丽’、‘马修’]
    呼叫排序(g:扬声器)
    函数!JoinAllSpeakLines()
    在整个文件中,将两个大写扬声器名称之间的所有行连接起来
    后跟“:”,第一个包含:
    静默g/\u\{2,}:/call JoinSpeakLines
    endf
    函数!SortSpeakLines()
    “按发言人对整个文件进行排序,保持
    “每位发言者。
    “必须在JoinAllSpeakLines()之后调用。
    “创建一个新的dict,每个扬声器一个键:
    设speakerlines={}
    对于g中的演讲者:演讲者
    让speakerlines[扬声器]=[]
    外循环
    “对于文件中的每一行:
    对于getline中的行(1,“$”)
    let speaker=GetSpeaker(行)
    如果演讲者=“”
    持续
    恩迪夫
    “将该行添加到右侧扬声器:
    呼叫添加(speakerlines[扬声器],线路)
    外循环
    “删除当前缓冲区中的所有内容:
    正常gg“_dG
    “添加已排序的行,每个发言者:
    对于g中的演讲者:演讲者
    调用附加(行(“$”),speakerlines[speaker])
    外循环
    “删除缓冲区中的第一行(空):
    正常gg“\u dd
    endf
    功能!GetOtherSpeakerPattern(扬声器)
    “返回一个模式,该模式匹配除
    “一个参数。
    “创建一个新列表,删除:演讲者:
    让他人=复制(g:发言者)
    设idx=索引(其他,a:扬声器)
    如果idx!=-1
    呼叫删除(其他,idx)
    恩迪夫
    创建并返回模式列表,如下所示
    “这个:“\v |…”
    调用映射(其他,'printf(“:”,v:val)'
    返回“\v”。加入(其他“|”)
    endf
    函数!获取扬声器(线路)
    返回一行中后跟“:”的大写名称
    返回matchstr(a:line'\u\{2,}\ze:')
    endf
    功能!JoinSpeakLines_uuu()
    当光标位于带有大写名称的行上时,将所有
    “以下几行