@@ -10,9 +10,13 @@ export function parseCrnList(text) {
1010 if ( ! text || typeof text !== 'string' ) return [ ] ;
1111
1212 const entries = [ ] ;
13+ const normalize = ( value ) => String ( value || '' )
14+ . replace ( / \u00a0 / g, ' ' )
15+ . replace ( / \s + / g, ' ' )
16+ . trim ( ) ;
1317
1418 for ( const rawLine of text . split ( / \r ? \n / ) ) {
15- const line = rawLine . trim ( ) ;
19+ const line = normalize ( rawLine ) ;
1620 if ( ! line ) continue ;
1721
1822 // Standard course format: CODE-NUMBER (section/crn) - name
@@ -21,37 +25,58 @@ export function parseCrnList(text) {
2125 ) ;
2226
2327 if ( standard ) {
24- entries . push ( {
25- courseCode : standard [ 1 ] . toUpperCase ( ) ,
26- courseNumber : standard [ 2 ] ,
27- crn : standard [ 3 ] . trim ( ) . toUpperCase ( ) ,
28- courseName : standard [ 4 ] . trim ( ) ,
29- source : line
30- } ) ;
28+ const crn = normalize ( standard [ 3 ] ) . toUpperCase ( ) ;
29+ if ( crn ) {
30+ entries . push ( {
31+ courseCode : standard [ 1 ] . toUpperCase ( ) ,
32+ courseNumber : standard [ 2 ] ,
33+ crn,
34+ courseName : normalize ( standard [ 4 ] ) ,
35+ source : rawLine . trim ( )
36+ } ) ;
37+ }
3138 continue ;
3239 }
3340
34- // Tabular university copy/paste format :
35- // No. | Course name | Code | Number | Section/CRN | Units
36- const cells = line . split ( '\t' ) . map ( cell => cell . trim ( ) ) ;
41+ // University table copy/paste:
42+ // No. | Course name | Code | Number | Section/CRN | Units | ...
43+ const cells = rawLine . split ( '\t' ) . map ( cell => normalize ( cell ) ) ;
3744 if ( cells . length >= 5 ) {
3845 const start = / ^ \d + $ / . test ( cells [ 0 ] ) ? 1 : 0 ;
3946 const courseName = cells [ start ] || '' ;
4047 const courseCode = cells [ start + 1 ] || '' ;
4148 const courseNumber = cells [ start + 2 ] || '' ;
4249 const crn = cells [ start + 3 ] || '' ;
4350
44- if ( / ^ [ A - Z a - z ] [ A - Z a - z 0 - 9 ] * $ / . test ( courseCode ) && / ^ \d + $ / . test ( courseNumber ) && crn ) {
51+ if ( / ^ [ A - Z a - z ] [ A - Z a - z 0 - 9 ] * $ / . test ( courseCode )
52+ && / ^ \d + $ / . test ( courseNumber )
53+ && / ^ [ A - Z a - z 0 - 9 ] + $ / . test ( crn ) ) {
4554 entries . push ( {
4655 courseCode : courseCode . toUpperCase ( ) ,
4756 courseNumber,
4857 crn : crn . toUpperCase ( ) ,
4958 courseName,
50- source : line
59+ source : rawLine . trim ( )
5160 } ) ;
5261 continue ;
5362 }
5463 }
64+
65+ // Same table copied with spaces instead of tabs. Course name may contain spaces,
66+ // so locate the code/number/CRN triplet rather than splitting the name blindly.
67+ const spaced = line . match (
68+ / ^ (?: \d + \s + ) ? ( .+ ?) \s + ( [ A - Z a - z ] [ A - Z a - z 0 - 9 ] * ) \s + ( \d + ) \s + ( [ A - Z a - z 0 - 9 ] + ) (?: \s + \d + ) ? $ /
69+ ) ;
70+
71+ if ( spaced ) {
72+ entries . push ( {
73+ courseCode : spaced [ 2 ] . toUpperCase ( ) ,
74+ courseNumber : spaced [ 3 ] ,
75+ crn : spaced [ 4 ] . toUpperCase ( ) ,
76+ courseName : normalize ( spaced [ 1 ] ) ,
77+ source : rawLine . trim ( )
78+ } ) ;
79+ }
5580 }
5681
5782 return entries ;
0 commit comments