curlkun commited on
Commit
b0e80ef
·
verified ·
1 Parent(s): 699b291

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +100 -244
app.py CHANGED
@@ -1,6 +1,5 @@
1
- # verify_bug2.py
2
  # 実行方法: python verify_bug2.py
3
- # 前提: app.py と同じディレクトリに配置して実行
4
 
5
  import re
6
  import difflib
@@ -144,12 +143,6 @@ def build_active_text_and_map(original, flags):
144
  index_map = [i for i, _ in active_chars]
145
  return active_text, index_map
146
 
147
- def build_removed_text_and_map(original, flags):
148
- removed_chars = [(i, ch) for i, ch in enumerate(original) if not flags[i]]
149
- removed_text = ''.join(ch for _, ch in removed_chars)
150
- index_map = [i for i, _ in removed_chars]
151
- return removed_text, index_map
152
-
153
  def tokenize(text):
154
  pattern = re.compile(
155
  r'[a-zA-ZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]+|'
@@ -195,7 +188,7 @@ def compare_texts(src, dst, settings):
195
 
196
  if src_active != '' or dst_active != '':
197
  # ---- トークン単位で比較 ----
198
- src_tokens = tokenize(src_active) # [(token_str, pos_in_active), ...]
199
  dst_tokens = tokenize(dst_active)
200
 
201
  src_token_strs = [t[0] for t in src_tokens]
@@ -204,32 +197,21 @@ def compare_texts(src, dst, settings):
204
  matcher = difflib.SequenceMatcher(None, src_token_strs, dst_token_strs, autojunk=False)
205
  for tag, i1, i2, j1, j2 in matcher.get_opcodes():
206
  if tag in ('replace', 'delete') and i2 > i1:
207
- # src_tokens[i1..i2-1] の元テキスト位置を求める
208
- start_in_active = src_tokens[i1][1]
209
- end_in_active = src_tokens[i2-1][1] + len(src_tokens[i2-1][0])
210
- orig_start = src_map[start_in_active]
211
- orig_end = src_map[end_in_active - 1] + 1
 
212
  src_diff_ranges.append((orig_start, orig_end))
213
  if tag in ('replace', 'insert') and j2 > j1:
214
- start_in_active = dst_tokens[j1][1]
215
- end_in_active = dst_tokens[j2-1][1] + len(dst_tokens[j2-1][0])
216
- orig_start = dst_map[start_in_active]
217
- orig_end = dst_map[end_in_active - 1] + 1
218
  dst_diff_ranges.append((orig_start, orig_end))
219
 
220
- # 除去文字の比較
221
- src_removed, src_removed_map = build_removed_text_and_map(src, src_flags)
222
- dst_removed, dst_removed_map = build_removed_text_and_map(dst, dst_flags)
223
-
224
- if src_removed != dst_removed and (src_active != '' or dst_active != ''):
225
- rm_matcher = difflib.SequenceMatcher(None, src_removed, dst_removed, autojunk=False)
226
- for tag, i1, i2, j1, j2 in rm_matcher.get_opcodes():
227
- if tag in ('replace', 'delete') and i2 > i1:
228
- for k in range(i1, i2):
229
- src_diff_ranges.append((src_removed_map[k], src_removed_map[k] + 1))
230
- if tag in ('replace', 'insert') and j2 > j1:
231
- for k in range(j1, j2):
232
- dst_diff_ranges.append((dst_removed_map[k], dst_removed_map[k] + 1))
233
 
234
  has_diff = bool(src_diff_ranges or dst_diff_ranges)
235
 
@@ -261,11 +243,10 @@ def compare_texts(src, dst, settings):
261
  return src_html, dst_html, has_diff
262
 
263
  # ============================================================
264
- # ハイライト範囲を文字列で返すヘルパー
265
  # ============================================================
266
 
267
  def extract_highlighted(text, html_result):
268
- """HTMLからハイライトされた文字列リストを抽出"""
269
  pattern = re.compile(r'<span style="[^"]*">(.+?)</span>', re.DOTALL)
270
  results = []
271
  for m in pattern.finditer(html_result):
@@ -275,7 +256,6 @@ def extract_highlighted(text, html_result):
275
 
276
  def run_test(name, src, dst, settings, expect_src_hl, expect_dst_hl, expect_has_diff):
277
  src_html, dst_html, has_diff = compare_texts(src, dst, settings)
278
-
279
  src_hl = extract_highlighted(src, src_html)
280
  dst_hl = extract_highlighted(dst, dst_html)
281
 
@@ -295,7 +275,7 @@ def run_test(name, src, dst, settings, expect_src_hl, expect_dst_hl, expect_has_
295
  if not ok_diff:
296
  print(f" [has_diff] 期待: {expect_has_diff} / 実際: {has_diff}")
297
 
298
- OFF = {} # 全設定オフ
299
  ALL_ON = {
300
  'ignore_alpha': True, 'ignore_digit': True, 'ignore_kana': True,
301
  'ignore_yakumono': True, 'ignore_ligature': True, 'ignore_kangxi': True,
@@ -309,217 +289,93 @@ ALL_ON = {
309
  # ============================================================
310
 
311
  print("=" * 60)
312
- print("バグ2 検証スクリプト")
313
  print("=" * 60)
314
 
315
- # TEST-01 相違なし
316
- run_test(
317
- "TEST-01 相違なし",
318
- src="吾輩は猫である。名前はまだない。",
319
- dst="吾輩は猫である。名前はまだない。",
320
- settings=OFF,
321
- expect_src_hl=[],
322
- expect_dst_hl=[],
323
- expect_has_diff=False,
324
- )
325
-
326
- # TEST-02 相違あり基本
327
- run_test(
328
- "TEST-02 相違あり基本",
329
- src="吾輩は猫である。",
330
- dst="吾輩は犬である。",
331
- settings=OFF,
332
- expect_src_hl=["猫"],
333
- expect_dst_hl=["犬"],
334
- expect_has_diff=True,
335
- )
336
-
337
- # TEST-03 比較先に追加
338
- run_test(
339
- "TEST-03 比較先に追加",
340
- src="abcdef",
341
- dst="abcXYZdef",
342
- settings=OFF,
343
- expect_src_hl=[],
344
- expect_dst_hl=["XYZ"],
345
- expect_has_diff=True,
346
- )
347
-
348
- # TEST-04 比較元に削除
349
- run_test(
350
- "TEST-04 比較元に削除",
351
- src="abcXYZdef",
352
- dst="abcdef",
353
- settings=OFF,
354
- expect_src_hl=["XYZ"],
355
- expect_dst_hl=[],
356
- expect_has_diff=True,
357
- )
358
-
359
- # TEST-08 約物全半角無視
360
- run_test(
361
- "TEST-08 約物全半角無視",
362
- src="吾輩は、猫である。「名前」は(まだ)ない!",
363
- dst="吾輩は猫である名前はまだない",
364
- settings={'ignore_yakumono': True},
365
- expect_src_hl=[],
366
- expect_dst_hl=[],
367
- expect_has_diff=False,
368
- )
369
-
370
- # TEST-09 約物括弧の中身は残る
371
- run_test(
372
- "TEST-09 約物括弧の中身は残る",
373
- src="(abc)テスト",
374
- dst="abcテスト",
375
- settings={'ignore_yakumono': True},
376
- expect_src_hl=[],
377
- expect_dst_hl=[],
378
- expect_has_diff=False,
379
- )
380
-
381
- # TEST-19 ハイフン無視
382
- run_test(
383
- "TEST-19 ハイフン無視",
384
- src="abc-def-ghi\u2010jkl\u2011mno\u2013pqr\u2014stu",
385
- dst="abcdefghijklmnopqrstu",
386
- settings={'ignore_hyphen': True},
387
- expect_src_hl=[],
388
- expect_dst_hl=[],
389
- expect_has_diff=False,
390
- )
391
-
392
- # TEST-21 スペース削除
393
- run_test(
394
- "TEST-21 スペース削除",
395
- src="abc def ghi",
396
- dst="abcdefghi",
397
- settings={'ignore_space': True},
398
- expect_src_hl=[],
399
- expect_dst_hl=[],
400
- expect_has_diff=False,
401
- )
402
-
403
- # TEST-21 スペース削除 設定オフ(スペースが差分)
404
- run_test(
405
- "TEST-21 スペース削除 設定オフ",
406
- src="abc def ghi",
407
- dst="abcdefghi",
408
- settings=OFF,
409
- expect_src_hl=[" ", " "],
410
- expect_dst_hl=[],
411
- expect_has_diff=True,
412
- )
413
-
414
- # TEST-22 改行削除
415
- run_test(
416
- "TEST-22 改行削除",
417
- src="abc\ndef\nghi",
418
- dst="abcdefghi",
419
- settings={'ignore_newline': True},
420
- expect_src_hl=[],
421
- expect_dst_hl=[],
422
- expect_has_diff=False,
423
- )
424
-
425
- # TEST-23 約物と括弧付き文字両方
426
- run_test(
427
- "TEST-23 約物と括弧付き文字両方",
428
- src="吾輩は(猫)である。名前は【まだ】ない!",
429
- dst="吾輩はである。名前はない!",
430
- settings={'ignore_yakumono': True, 'ignore_brackets_with_content': True},
431
- expect_src_hl=[],
432
- expect_dst_hl=[],
433
- expect_has_diff=False,
434
- )
435
-
436
- # TEST-25 全設定オフ(バグ2メイン修正対象)
437
- run_test(
438
- "TEST-25 全設定オフ",
439
- src="abc(def)123アイウ〔ghi〕fi\u2F00zero-test \nabc",
440
- dst="xyz(www)789カキクケコ〔jkl〕fl\u2F01one+test \nxyz",
441
- settings=OFF,
442
- expect_src_hl=["abc", "def", "123", "アイウ", "ghi", "fi", "\u2F00", "zero"],
443
- expect_dst_hl=["xyz", "www", "789", "カキクケコ", "jkl", "fl", "\u2F01", "one", "+"],
444
- expect_has_diff=True,
445
- )
446
-
447
- # TEST-25 全設定オン
448
- run_test(
449
- "TEST-25 全設定オン",
450
- src="abc(def)123アイウ〔ghi〕fi\u2F00zero-test \nabc",
451
- dst="xyz(www)789カキクケコ〔jkl〕fl\u2F01one+test \nxyz",
452
- settings=ALL_ON,
453
- expect_src_hl=[],
454
- expect_dst_hl=[],
455
- expect_has_diff=False,
456
- )
457
-
458
- # TEST-30 スペースのみ相違 設定オフ
459
- run_test(
460
- "TEST-30 スペースのみ相違 設定オフ",
461
- src="abc def",
462
- dst="abcdef",
463
- settings=OFF,
464
- expect_src_hl=[" "],
465
- expect_dst_hl=[],
466
- expect_has_diff=True,
467
- )
468
-
469
- # TEST-35 比較元削除箇所ハイライト
470
- run_test(
471
- "TEST-35 比較元削除箇所ハイライト",
472
- src="abcXYZdef",
473
- dst="abcdef",
474
- settings=OFF,
475
- expect_src_hl=["XYZ"],
476
- expect_dst_hl=[],
477
- expect_has_diff=True,
478
- )
479
-
480
- # TEST-37 ハイフン全種
481
- run_test(
482
- "TEST-37 ハイフン全種",
483
- src="abc-def\uFF0Dghi\u2010jkl\u2011mno\u2013pqr\u2014stu",
484
- dst="abcdefghijklmnopqrstu",
485
- settings={'ignore_hyphen': True},
486
- expect_src_hl=[],
487
- expect_dst_hl=[],
488
- expect_has_diff=False,
489
- )
490
-
491
- # TEST-27 空文字
492
- run_test(
493
- "TEST-27 空文字",
494
- src="",
495
- dst="",
496
- settings=OFF,
497
- expect_src_hl=[],
498
- expect_dst_hl=[],
499
- expect_has_diff=False,
500
- )
501
-
502
- # TEST-28 片方空文字
503
- run_test(
504
- "TEST-28 片方空文字",
505
- src="abcdef",
506
- dst="",
507
- settings=OFF,
508
- expect_src_hl=["abcdef"],
509
- expect_dst_hl=[],
510
- expect_has_diff=True,
511
- )
512
-
513
- # TEST-29 改行のみ相違 設定オフ
514
- run_test(
515
- "TEST-29 改行のみ相違 設定オフ",
516
- src="\n\n",
517
- dst="\n",
518
- settings=OFF,
519
- expect_src_hl=["\n"],
520
- expect_dst_hl=[],
521
- expect_has_diff=True,
522
- )
523
 
524
  print("=" * 60)
525
  print("完了")
 
1
+ # verify_bug2.py ver2
2
  # 実行方法: python verify_bug2.py
 
3
 
4
  import re
5
  import difflib
 
143
  index_map = [i for i, _ in active_chars]
144
  return active_text, index_map
145
 
 
 
 
 
 
 
146
  def tokenize(text):
147
  pattern = re.compile(
148
  r'[a-zA-ZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]+|'
 
188
 
189
  if src_active != '' or dst_active != '':
190
  # ---- トークン単位で比較 ----
191
+ src_tokens = tokenize(src_active)
192
  dst_tokens = tokenize(dst_active)
193
 
194
  src_token_strs = [t[0] for t in src_tokens]
 
197
  matcher = difflib.SequenceMatcher(None, src_token_strs, dst_token_strs, autojunk=False)
198
  for tag, i1, i2, j1, j2 in matcher.get_opcodes():
199
  if tag in ('replace', 'delete') and i2 > i1:
200
+ # active_text内の開始・終了位置
201
+ a_start = src_tokens[i1][1]
202
+ a_end = src_tokens[i2-1][1] + len(src_tokens[i2-1][0])
203
+ # src_map で元テキスト位置に変換
204
+ orig_start = src_map[a_start]
205
+ orig_end = src_map[a_end - 1] + 1
206
  src_diff_ranges.append((orig_start, orig_end))
207
  if tag in ('replace', 'insert') and j2 > j1:
208
+ a_start = dst_tokens[j1][1]
209
+ a_end = dst_tokens[j2-1][1] + len(dst_tokens[j2-1][0])
210
+ orig_start = dst_map[a_start]
211
+ orig_end = dst_map[a_end - 1] + 1
212
  dst_diff_ranges.append((orig_start, orig_end))
213
 
214
+ # ※除去文字の比較は行わない(無視設定した文字はハイライト対象外)
 
 
 
 
 
 
 
 
 
 
 
 
215
 
216
  has_diff = bool(src_diff_ranges or dst_diff_ranges)
217
 
 
243
  return src_html, dst_html, has_diff
244
 
245
  # ============================================================
246
+ # ヘルパー・テスト実行関数
247
  # ============================================================
248
 
249
  def extract_highlighted(text, html_result):
 
250
  pattern = re.compile(r'<span style="[^"]*">(.+?)</span>', re.DOTALL)
251
  results = []
252
  for m in pattern.finditer(html_result):
 
256
 
257
  def run_test(name, src, dst, settings, expect_src_hl, expect_dst_hl, expect_has_diff):
258
  src_html, dst_html, has_diff = compare_texts(src, dst, settings)
 
259
  src_hl = extract_highlighted(src, src_html)
260
  dst_hl = extract_highlighted(dst, dst_html)
261
 
 
275
  if not ok_diff:
276
  print(f" [has_diff] 期待: {expect_has_diff} / 実際: {has_diff}")
277
 
278
+ OFF = {}
279
  ALL_ON = {
280
  'ignore_alpha': True, 'ignore_digit': True, 'ignore_kana': True,
281
  'ignore_yakumono': True, 'ignore_ligature': True, 'ignore_kangxi': True,
 
289
  # ============================================================
290
 
291
  print("=" * 60)
292
+ print("バグ2 検証スクリプト ver2")
293
  print("=" * 60)
294
 
295
+ run_test("TEST-01 相違なし",
296
+ "吾輩は猫である。名前はまだない。",
297
+ "吾輩は猫である。名前はまだない。",
298
+ OFF, [], [], False)
299
+
300
+ run_test("TEST-02 相違あり基本",
301
+ "吾輩は猫である。",
302
+ "吾輩は犬である。",
303
+ OFF, ["猫"], ["犬"], True)
304
+
305
+ run_test("TEST-03 比較先に追加",
306
+ "abcdef", "abcXYZdef",
307
+ OFF, [], ["XYZ"], True)
308
+
309
+ run_test("TEST-04 比較元に削除",
310
+ "abcXYZdef", "abcdef",
311
+ OFF, ["XYZ"], [], True)
312
+
313
+ run_test("TEST-08 約物全半角無視",
314
+ "吾輩は、猫である。「名前」は(まだ)ない!",
315
+ "吾輩は猫である名前はまだない",
316
+ {'ignore_yakumono': True}, [], [], False)
317
+
318
+ run_test("TEST-09 約物括弧の中身は残る",
319
+ "(abc)テスト", "abcテスト",
320
+ {'ignore_yakumono': True}, [], [], False)
321
+
322
+ run_test("TEST-19 ハイフン無視",
323
+ "abc-def\uFF0Dghi\u2010jkl\u2011mno\u2013pqr\u2014stu",
324
+ "abcdefghijklmnopqrstu",
325
+ {'ignore_hyphen': True}, [], [], False)
326
+
327
+ run_test("TEST-21 スペース削除 設定オン",
328
+ "abc def ghi", "abcdefghi",
329
+ {'ignore_space': True}, [], [], False)
330
+
331
+ run_test("TEST-21 スペース削除 設定オフ",
332
+ "abc def ghi", "abcdefghi",
333
+ OFF, [" ", " "], [], True)
334
+
335
+ run_test("TEST-22 改行削除 設定オン",
336
+ "abc\ndef\nghi", "abcdefghi",
337
+ {'ignore_newline': True}, [], [], False)
338
+
339
+ run_test("TEST-23 約物と括弧付き文字両方",
340
+ "吾輩は(猫)である。名前は【まだ】ない!",
341
+ "吾輩はである。名前はない!",
342
+ {'ignore_yakumono': True, 'ignore_brackets_with_content': True},
343
+ [], [], False)
344
+
345
+ run_test("TEST-25 全設定オフ",
346
+ "abc(def)123アイウ〔ghi〕fi\u2F00zero-test \nabc",
347
+ "xyz(www)789カキクケコ〔jkl〕fl\u2F01one+test \nxyz",
348
+ OFF,
349
+ ["abc", "def", "123", "アイウ", "ghi", "fi", "\u2F00", "zero"],
350
+ ["xyz", "www", "789", "カキクケコ", "jkl", "fl", "\u2F01", "one", "+"],
351
+ True)
352
+
353
+ run_test("TEST-25 全設定オン",
354
+ "abc(def)123アイウ〔ghi〕fi\u2F00zero-test \nabc",
355
+ "xyz(www)789カキクケコ〔jkl〕fl\u2F01one+test \nxyz",
356
+ ALL_ON, [], [], False)
357
+
358
+ run_test("TEST-30 スペースのみ相違 設定オフ",
359
+ "abc def", "abcdef",
360
+ OFF, [" "], [], True)
361
+
362
+ run_test("TEST-35 比較元削除箇所ハイライト",
363
+ "abcXYZdef", "abcdef",
364
+ OFF, ["XYZ"], [], True)
365
+
366
+ run_test("TEST-37 ハイフン全種 設定オン",
367
+ "abc-def\uFF0Dghi\u2010jkl\u2011mno\u2013pqr\u2014stu",
368
+ "abcdefghijklmnopqrstu",
369
+ {'ignore_hyphen': True}, [], [], False)
370
+
371
+ run_test("TEST-27 空文字",
372
+ "", "", OFF, [], [], False)
373
+
374
+ run_test("TEST-28 片方空文字",
375
+ "abcdef", "", OFF, ["abcdef"], [], True)
376
+
377
+ run_test("TEST-29 改行のみ相違 設定オフ",
378
+ "\n\n", "\n", OFF, ["\n"], [], True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
 
380
  print("=" * 60)
381
  print("完了")