[BUG] handle } in line delimited json
- [x] closes #14390
- [x] tests added / passed
- [x] passes `git diff upstream/master | flake8 --diff`
- [x] whatsnew entry

## [Current coverage](https://codecov.io/gh/pydata/pandas/pull/14391?src=pr) is 85.26% (diff: 100%)

> Merging [#14391](https://codecov.io/gh/pydata/pandas/pull/14391?src=pr) into [master](https://codecov.io/gh/pydata/pandas/branch/master?src=pr) will increase coverage by **<.01%**

``` diff
@@             master     #14391   diff @@
==========================================
  Files           140        140          
  Lines         50634      50639     +5   
  Methods           0          0          
  Messages          0          0          
  Branches          0          0          
==========================================
+ Hits          43173      43178     +5   
  Misses         7461       7461          
  Partials          0          0          
```

> Powered by [Codecov](https://codecov.io?src=pr). Last update [d98e982...edb1488](https://codecov.io/gh/pydata/pandas/compare/d98e982ecb0f6b7f3478a63caac34e0be238895c...edb148824da7a321c6e76abf464a6993fe7be714?src=pr)
 can you add a benchmark for `lines=True` in `asv_bench/benchmarks/packers.py` (alongside the other json ones)
 Not sure why that test failed,, the only change was a line of whitespace
 @joshowen can you also post a run for this benchmark (versus previous); can also do it in a %timeit as well. Just checking if any perf issues.
 @jreback is there an easy way to do that?  Or should I port the asv test to master and run/compare?
 you _can_ run asv if you want, otherwise just do it in ipython (before and after), e.g. something like

```
In [6]: df = DataFrame(dict([('float{0}'.format(i), np.random.randn(N)) for i in range(C)]), index=index).reset_index(drop=True)

In [7]: df.to_json('foo.json',orient='records',lines=True)

In [8]: %timeit df.to_json('foo.json',orient='records',lines=True)
1 loop, best of 3: 3.66 s per loop

In [9]: %timeit df.to_json('foo.json',orient='records')
10 loops, best of 3: 98.8 ms per loop

```

and looking at this, we have a BIG perf hit when `lines=True` (this is a separate issue).
 cc @aterrel 
 @joshowen can you open another issue about the perf 

```
In [15]: %prun df.to_json('foo.json',orient='records',lines=True)
         100058 function calls (100056 primitive calls) in 3.759 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    2.017    2.017    3.656    3.656 json.py:600(_convert_to_line_delimits)
        1    1.002    1.002    1.002    1.002 {method 'join' of 'str' objects}
        1    0.630    0.630    0.630    0.630 {numpy.core.multiarray.array}
        1    0.078    0.078    0.078    0.078 {pandas.json.dumps}
        1    0.012    0.012    0.012    0.012 {method 'write' of 'file' objects}
```

something odd going on here
 lgtm. @jorisvandenbossche 
 Thanks @joshowen !
