【问题标题】:JavaScript Regex replace words with their first letter except when within parenthesesJavaScript 正则表达式用它们的第一个字母替换单词,除非在括号内
【发布时间】:2015-04-06 00:10:52
【问题描述】:

我正在寻找 JavaScript 正则表达式,它将仅用每个单词的第一个字母替换文本块中的单词,但是如果括号内有单词,则用括号将它们保持原样。 目的是创建一个助记装置,用于记住剧本或戏剧剧本中的台词。我希望将实际线条减少到第一个字母,但舞台方向(括号中)保持不变。

例如:

Test test test (test). Test (test test) test test.

会产生结果:

T t t (test). T (test test) t t.

使用:

 .replace(/(\w)\w*/g,'$1')

产量:

T t t (t). T (t t) t t.

我对正则表达式的理解很差。我已经研究了几天,尝试了很多东西,但似乎无法找到解决方案。

【问题讨论】:

    标签: javascript regex replace parentheses


    【解决方案1】:

    您可以通过对正则表达式稍作调整来完成此操作:

    /(\w|\([^)]+\))\w*/
    

    添加的部分\([^)]+\) 匹配两对括号内的所有内容。

    "Test test test (test). Test (test test) test test.".replace(/(\w|\([^)]+\))\w*/g,'$1')
    >"T t t (test). T (test test) t t."
    

    编辑:解决 cmets 中提出的问题

    "Test test test (test). Test (test. test.) test test. test(test) (test)test".replace(/(\w|\([^)]+)\w*/g,'$1')
    >"T t t (test). T (test. test.) t t. t(test) (test)t"
    

    【讨论】:

    • 这是尽可能紧凑的,但如果右括号后面没有空格,则将失败,如果这是一个问题的话。例如,Test (test)test test" 产生 "T (test) t"
    • @torazaburo:确实,但是这个问题可以很容易地用非单词边界来解决:(\w|\([^)]*\))\B\w*
    • @Casimir et Hippolyte:按照建议使用非单词边界将括号中的文本呈现为仅当非括号单词紧跟在右括号之后但不是紧接在左括号之前时的第一个字母.例如,'test(test) (test)test' 产生 't(test) (t)t'
    • @Grewu:使其成为可选:(\w|\([^)]*\))(?:\B\w+)?
    • @dwickern: \B 不是字符,你不能把它放在字符类中,也没有必要。省略右括号是个好主意。
    【解决方案2】:

    为了保持正则表达式简单,您可以使用回调机制来跟踪左括号和右括号:

    var t = 'Test test test (test). Test (test test) test test.';
    
    // keep track of open state and last index
    
    var s = {
      open: false,
      index: 0
    };  
        
    var res = t.replace(/\w+/g, function($0, index) {
      // update state
      for (var i = s.index; i < index; ++i) {
        if (t[i]=='(' || t[i] == ')') {
          s.open = !s.open; // assume balanced parentheses
        }
      }
      s.index = index;
      // return first letter if outside of parentheses
      return s.open ? $0 : $0[0];
    });
    
    console.log(res);

    【讨论】:

    • 这正是我需要的。
    【解决方案3】:

    在这种情况下,有三种方法:

    1. 使用正则表达式查找您想要保留的所有内容,然后将所有这些部分粘贴在一起。

    2. 使用正则表达式查找您不想保留的东西,然后通过替换它们将它们扔掉(这是其他一些答案所做的)。

    3. 按照一个答案的建议,自己解析字符串。

    我们将考虑正则表达式解决方案。编写正则表达式的关键是写下你想要它做什么的叙述性描述。然后将其转换为实际的正则表达式语法。否则,当你随意尝试一件事或另一件事时,你的眼睛会开始流血。

    要找到你想保留的东西,叙述性描述是:

    任何带括号的字符串(包括前面的空格)空格(或字符串开头)后跟单个字母、标点符号。

    把它变成一个正则表达式:

    including preceding spaces:   \s*
    any parenthesized string:     \(.*?\)
    or:                           |
    space or beginning of string: (^|\s+)
    any letter:                   \w
    punctuation:                  [.]
    

    所以相关的正则表达式是/\s*\(.*?\)|(^|\s+)\w|[.]/

    >> parts = str.match(/\s*\(.*?\)|(^|\s+)\w/g);
    << ["T", " t", " t", " (test)", ".", " T", " (test test)", " t", " t", "."]
    
    >> parts.join('')
    << "T t t (test). T (test test) t t."
    

    如果你想采用相反的方法,即找到你不想保留的部分,用空字符串替换,那么叙述是

    任何前面有另一个字母的字母,除非更早有一个左括号,中间没有右括号。

    这里的问题是 unless come early 部分,在正则表达式中,这就是所谓的否定后视;正则表达式的 JS 风格不支持。

    这就是为什么其他一些答案使用正则表达式的技术,即“(1)第一个字母或括号表达式的整个序列,(2)后跟更多字母”,并捕获(1)部分。然后用 (1) 替换整个字符串,使用 $1 反向引用,它具有删除 (2) 的效果。这也很好用。

    换句话说,要丢弃A(如果前面有B),它们会匹配(B)A,然后将整个匹配替换为B

    使用split

    为了完整起见,您还可以考虑使用空格、标点符号和括号括起来的表达式:

    str = "Test (test). test";
    
    >> pieces = str.split(/(\(.*?\)|\s+|[.])/);
    << ["Test", " ", "", "(test)", "", ".", "", " ", "test"]
    
    // Remove empty strings
    >> pieces = pieces . filter(Boolean)
    << ["Test", " ", "(test)", ".", " ", "test"]
    
    // Take first letter if not parenthesized
    >> pieces = pieces . map(function(piece) {
         return piece[0] === '(' ? piece : piece[0];
        });
    << ["T", " ", "(test)", ".", " ", "t"]
    
    // Join them back together
    >> pieces . join('')
    << "T (test). t"
    

    整个解决方案就变成了

    function abbreviate_words_outside_parentheses(str) {
      return str .
        split(/(\(.*?\)|\s+|[.])/) .
        filter(Boolean) .
        map(function(piece) { return piece[0] === '(' ? piece : piece[0];  }) .
        join('')
      ;
    }
    

    如果您认为将来可能希望进行其他类型的转换,这种程序方法可能更可取,这可能很难使用正则表达式处理。

    【讨论】:

    • 如何修改这些解决方案以在结果中包含所需的标点符号?
    • 我修改了您添加的内容,包括感叹号和问号“[.!\?]”。现在,“拆分”示例非常适用于我能想象到的任何场景。第一个示例适用于所有场景,除非右括号和下一个单词之间没有空格。因此,虽然 Test(test) 产生 T(test),但 (test)Test 只产生 (test)。不过,这种情况可能很少见。
    【解决方案4】:

    您需要使用捕获组和前瞻断言来获得预期的结果。

    > "Test test test (test). Test (test test) test test".replace(/(^[^\s(]|\s[^\s(])[^()\s]*(?=\s|$)/g, "$1")
    'T t t (test). T (test test) t t'
    

    DEMO

    • (^[^\s(]|\s[^\s(]) 捕获每个单词的第一个字母,不能是空格或(

    • [^()\s]* 匹配任何字符,但不匹配() 或空格。

    • (?=\s|$)positive lookahead 断言匹配后必须跟一个空格或行尾锚,这反过来意味着我们匹配一个完整的单词。

    【讨论】:

      猜你喜欢
      • 2011-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-19
      • 1970-01-01
      相关资源
      最近更新 更多